UVA

来源:互联网 发布:江苏开放大学网络教育 编辑:程序博客网 时间:2024/06/08 04:48

题目链接:uva12260

题目大意:有n个糖果,每个糖果有p,j两个值,现在有两个人Petra和Jan,Prtra的取糖果方式是优先去p值大的j值小的;Jan取糖果的方式是尽量让自己开心值(取出糖果的j值和)大的情况下让Petra的开心值(取出糖果的p值和)也大,给出先选糖果的人,问说最后两人的开心值分别为多少。

思路:因为petra的取法只需要考略当前糖果状态,而jan需要考略最终的结果,所以我们按照petra的取糖果顺序排序,即先按糖果的p值由大到小排序,然后按照j之由小到大排序。

接下来dp考略jan的取法。dp[i][j]代表jan取到第i个糖果时他一共选了j个糖果,他此时的j值为多少。(尽可能大)

val[i][j]代表jan取到第i个糖果时他一共选了j个糖果,他此时的p值为多少。(尽可能小)

首先需要考虑当要取第i个糖果的时候,jan最大能够取多少个糖果。分两种情况,首先petra先取的话,她能取num=i/2个,如果他先取的话能够取num=(i+1)/2;

然后就是一个简单的背包问题。

AC代码

/*题目大意:有n个糖果,每个糖果有p,j两个值,现在有两个人Petra和Jan,Prtra的取糖果方式是优先去p值大的j值小的;Jan取糖果的方式是尽量让自己开心值(取出糖果的j值和)大的情况下让Petra的开心值(取出糖果的p值和)也大,给出先选糖果的人,问说最后两人的开心值分别为多少。*/#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<queue>using namespace std;#define maxn 2000int n;char s[20];struct node{int p,j;}a[maxn];bool cmp(node x,node y){if(x.p==y.p)return x.j<y.j;return x.p>y.p;}int dp[maxn][maxn];int val[maxn][maxn];int sum;int main(){int t;scanf("%d",&t);while(t--){scanf("%d",&n);scanf("%s",s);sum=0;for(int i=1;i<=n;i++){scanf("%d%d",&a[i].p,&a[i].j);sum+=a[i].p;}sort(a+1,a+n+1,cmp);memset(dp,0,sizeof dp);memset(val,0,sizeof val);int num;//取到第i个糖果是  Jan最多取几个for(int i=1;i<=n;i++){if(s[0]=='P')num=i/2;elsenum=(i+1)/2;for(int j=1;j<=num;j++){if(dp[i-1][j]<dp[i-1][j-1]+a[i].j){dp[i][j]=dp[i-1][j-1]+a[i].j;val[i][j]=val[i-1][j-1]+a[i].p;}else if(dp[i-1][j]==dp[i-1][j-1]+a[i].j){if(val[i-1][j]>val[i-1][j-1]+a[i].p){val[i][j]=val[i-1][j-1]+a[i].p;}else val[i][j]=val[i-1][j];dp[i][j]=dp[i-1][j];}else{dp[i][j]=dp[i-1][j];val[i][j]=val[i-1][j];}}}int ans=0;int pos;for(int i=1;i<=n;i++){if(dp[n][i]>ans){ans=dp[n][i];pos=i;}}printf("%d %d\n",sum-val[n][pos],dp[n][pos]);}return 0;}/*34Petra100 8070 8050 8030 504Petra10 11 106 64 47Jan4 13 12 11 11 21 31 4*/


原创粉丝点击