uva 12260 Free Goodies DP+一点点贪心

来源:互联网 发布:淘宝买二手吉他靠谱吗 编辑:程序博客网 时间:2024/06/07 03:50

原题: 

Free Goodies

Petra and Jan have just received a box full of free goodies, and want todivide the goodies between them. However, it is not easy to do this fairly,since they both value different goodies differently.

To divide the goodies, they have decided upon the following procedure:they choose goodies one by one, in turn, until all the goodies are chosen. Acoin is tossed to decide who gets to choose the first goodie.

Petra and Jan have different strategies in deciding what to choose. Whenfaced with a choice, Petra always selects the goodie that is most valuable toher. In case of a tie, she is very considerate and picks the one that is leastvaluable to Jan. (Since Petra and Jan are good friends, they know exactly howmuch value the other places on each goodie.)

Jan's strategy, however, consists of maximizing his own final value. He isalso very considerate, so if multiple choices lead to the same optimal result,he prefers Petra to have as much final value as possible.

You are given the result of the initial coin toss. After Jan and Petrahave finished dividing all the goodies between themselves, what is the totalvalue of the goodies each of them ends up with?

Input

On the first line a positive integer: the number of test cases, at most100. After that per test case:

  • One line with an integer n (1 ≤ n ≤ 1 000): the number of goodies.
  • One line with a string, either "Petra" or "Jan": the person that chooses first.
  • n lines with two integers pi and ji (0 ≤ pi,ji ≤ 1 000) each: the values that Petra and Jan assign to the i-th goodie, respectively.

Output

Per test case:

  • One line with two integers: the value Petra gets and the value Jan gets. Both values must be according to their own valuations.

Sample in- and output

Input

Output

3

4

Petra

100 80

70 80

50 80

30 50

4

Petra

10 1

1 10

6 6

4 4

7

Jan

4 1

3 1

2 1

1 1

1 2

1 3

1 4

170 130

14 16

9 10

题意:P与J对那些东西都有自己认为的价值,然后会依次选取东西,P选取东西的策略就是先选价值最大的,如果一些东西的价值一样大,那么就选J认为的价值小的;J选取东西的策略就是尽可能的让自己得到的价值大,但是可能存在不同的选取方法让他得到的价值一样达到最大,但是P获得的价值可能会有所不同,J会选择那种保证自己能拿到最大价值且P能拿到最大价值的一种情况。

不知道这样说清不清楚。

解题思路:

第一,对于P的策略来说只需要一点点贪心来照顾一下就行了,因为他肯定是按照价值大小来选,只需给他排一下序便好。

第二,J的策略其实是选取的关键,因为他选择的多变,他可以“随心”选择他想选择的物品

比如:对于排好序的物品来说,1、如果J先取第一个,那么P会取第二个,如果J先去第二个,那么P就会选第一个。

2、在前两个基础上,如果J选了第三个,那么P就会选第四个;如果J选了第三个以外的物品,那么P就选择第三个。

...........

依次类推J最多能随心选i以前的多少个呢?

前1个,为1

前2个,为1

前3个,为2

前4个,为2

前5个,为3

前6个,为3

....

那么前n个,为(n+1)/2.

我们用dp[i][j]表示前i个,随心选j个物品的能获得的最大值

那么dp[i][j]=max(dp[i-1][j],dp[i-1][j-1]+y[i])【当dp[i-1][j-1]有意义的时候才能进入这个递归方程】

(举个例子说,前10个,J可能选了3个,也可以选4个,但是最多选5个,如果选3个也就说他会去10+里面多取一些,这也是这道题dp的意义,这个dp方程意思就是在J要取j个是情况下,是在第i个物品要不要拿,拿就要再j里分出一个名额,不拿就不用管它了。有点01背包的感觉)

另外,在保证J能取得最大值的情况下还要保证P能拿到最大值,要怎么做呢?当J拿走一个东西时,反过来想P就会失去X[I]的价值,这个是对的,那么我们就保证在J取(n+1)/2的物品时,P失去的价值最少即可。

那么我们新开一个cost[i][j]来维护就行了,(dp数组记录J的得到(y的值),cost数组记录P的失去(x的值)这样配套的来记录应该是很好理解的)

下面发一下代码:

#include<iostream>#include<stdio.h>#include<string.h>#include <algorithm>using namespace std;const int maxn=1005;struct COST{    int x,y;} a[maxn];int cost[maxn][maxn];int dp[maxn][maxn];int n;char op[10];bool cmp(COST a,COST b){    if(a.x>b.x)        return true;    else if(a.x==b.x)        return a.y<b.y;    return false;}int main(){    int t,sum,i,cur;    scanf("%d",&t);    while(t--)    {        sum=0;        scanf("%d",&n);        scanf("%s",op);        for(i=1; i<=n; i++)        {            scanf("%d%d",&a[i].x,&a[i].y);            sum+=a[i].x;        }        sort(a+1,a+n+1,cmp);        memset(dp,0,sizeof(dp));        memset(cost,0,sizeof(cost));        i=1;        cur=0;        if(op[0]=='P') i=2;        for(; i<=n; i++)        {            cur++;            for (int j = 1; j <= (cur+1)/2; ++j)            {                int &ans = dp[i][j] = dp[i-1][j];                cost[i][j] = cost[i-1][j];                if (j==1 || dp[i-1][j-1])//保证dp【i-1】【j-1】有意义                {                    int tmp = dp[i-1][j-1] + a[i].y;                    if (tmp > ans) //如果选了i比不选大                    {                        ans = tmp;                        cost[i][j] = cost[i-1][j-1] + a[i].x;//那么P铁定就要失去x了                    }                    else if (tmp == ans)//如果选了i跟不选i没区别,                    {                        cost[i][j] = min(cost[i][j], cost[i-1][j-1]+a[i].x);//那么就要考虑两种情况那种P失去的价值少                    }                }            }        }      printf("%d %d\n",sum-cost[n][(cur+1)/2],dp[n][(cur+1)/2]);    }return 0;}

0 0
原创粉丝点击