UVA 12260 Free Goodies (DP)

来源:互联网 发布:windows xp经典主题包 编辑:程序博客网 时间:2024/06/07 00:01

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


思路:我们可以知道Petra直接贪心选取即可。所以对糖果的p进行排序,就看Jan会取哪些糖果了,那么每个糖果就可以看成是Jan取不取,但是要注意,由于Petra是一定会取一个剩下的p最大的,所以Jan取糖果的时候是有一定的限制的,限制为:如果Jan先取,1个糖果,Jan可以拿到一个;2个糖果,Jan可以拿其中一个;3个糖果Jan可以拿其中2个;4个糖果也是2个...以此类推,Jan能拿的糖果数为(i + 1)/2。因此dp[i][j]表示Jan在前i个糖果中拿了j个,j <= (i + 1)/2.注意有先后手问题,我们只需考虑Jan先拿,如果Petra先拿就直接从第二个开始变成Jan先手。

转移方程:dp[i][j] = max(dp[i-1][j], dp[i-1][j-1]+a[i].y)取或不取


代码:

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;typedef long long ll;const int maxn = 1e3+5;char str[maxn];struct node{    int x, y;    bool operator < (const node &a) const    {        if(x == a.x)            return y < a.y;        else            return x > a.x;    }}a[maxn];int dp[maxn][maxn], cost[maxn][maxn];int main(void){    int t, n;    cin >> t;    while(t--)    {        scanf("%d", &n);        scanf(" %s", str);        int s = 1, sum = 0;        if(str[0] == 'P') s = 2;        for(int i = 1; i <= n; i++)            scanf("%d%d", &a[i].x, &a[i].y), sum += a[i].x;        sort(a+1, a+1+n);        int cur = 0;        memset(dp, 0, sizeof(dp));        for(int i = s; i <= n; i++)        {            cur++;            for(int j = 1; j <= (cur+1)/2; j++)            {                dp[i][j] = dp[i-1][j];                cost[i][j] = cost[i-1][j];                if(dp[i-1][j-1]+a[i].y > dp[i][j])                {                    dp[i][j] = dp[i-1][j-1]+a[i].y;                    cost[i][j] = cost[i-1][j-1]+a[i].x;                }                else if(dp[i-1][j-1]+a[i].y == dp[i][j])                    cost[i][j] = min(cost[i][j], cost[i-1][j-1]+a[i].x);            }        }        printf("%d %d\n", sum-cost[n][(cur+1)/2], dp[n][(cur+1)/2]);    }    return 0;}