原题:
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的策略其实是选取的关键,因为他选择的多变,他可以“随心”选择他想选择的物品
比如:对于排好序的物品来说,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;
}