题目描述:有n个人,需要从中选出m个人,每个人都有一个d和一个p值,要求选出来的m个人满足:在所有的方案中,所有人的p值之和减去所有人的d值之和的绝对值最小,如果最小的绝对值相等,则取p值之和加上d值之和最大的方案。
输入格式:有多组数据,每组数据n+1行,第一行两个整数n和m,接下来n行每行两个整数,表示每个人的d值和p值,以0 0结束输入。
输出格式:每组数据输出三行,第一行表示当前数据组数的字符串(“Jury #1”,”Jury #2”, etc.),第二行输出表示该方案的所有人的d值之和与p值之和的字符串(“Best jury has value P for prosecution and value D for defence:”),第三行输出该方案选出来的人的编号,每个人的编号之前都有一个空格。每组数据输出完之后输出一行空格。
数据约定:0 < n <= 200,0< m <= 20,0 <= p,q <= 20。
解题思路:DP!!!
状态:f[i][j]表示已经选出来了i个人并且差值为j时的最大和值。
转移:f[i+1][j+p[k]-d[k]] = max{f[i][j]+p[k]+d[k]},第一重循环i从1开始枚举,第二重循环j从-400枚举到+400(具体实现需要把j整体移400,C数组下标从0开始的),第三重循环k从1枚举到n。。。
一开始我以为是搜索。。妈蛋的谁叫前面的两道题都是搜索。。后来发现是DP,然后想了想状态和转移,发现还要记录路径,天坑。。。然后我就可耻的看了别人的题解。发现其实dp的时候带上路径并没有想象中的那么难。。但是不知道为什么讨论区好多人说标准的dp解法有错误。。不懂。。。。
我的代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAX_N 222
int main(int argc, char const *argv[])
{
int m, n, cnt=0, p[MAX_N], d[MAX_N];
int ans[MAX_N][MAX_N*4], path[MAX_N][MAX_N*4];
while(scanf("%d%d", &n, &m) && n && m){
//preprocessing and get input
memset(ans,-1,sizeof(ans));
memset(path,-1,sizeof(path));
int zero=m*20; ans[0][zero]=0;
for(int i=0; i<n; ++i){ scanf("%d%d", p+i, d+i); }
// dynamic programming
for(int i=1; i<=m; ++i){
for(int j=0; j<=zero*2; ++j){
if(ans[i-1][j]==-1) { continue; }
for(int k=0; k<n; ++k){
int nums=i-1, value=j, flag=false;
while(nums>0){
int prev=path[nums][value];
--nums && (value-=p[prev]-d[prev]);
if(prev==k) { flag=true; break; }
}
if(flag) { continue; }
if(ans[i-1][j]+d[k]+p[k]>ans[i][j+p[k]-d[k]]){
ans[i][j+p[k]-d[k]]=ans[i-1][j]+d[k]+p[k];
path[i][j+p[k]-d[k]]=k;
}
}
}
}
//output the answer
int i=zero, j=0, k=zero, err, answer[MAX_N];
while(ans[m][i+j]<0 && ans[m][i-j]<0 && ++j);
err=(k=ans[m][i+j]>ans[m][i-j]?i+j:i-j)-zero;
printf("Jury #%d\n",++cnt);
printf("Best jury has value %d for prosecution and value %d for defence:\n",(err+ans[m][k])/2,(ans[m][k]-err)/2);
for(int i=0; i<m; ++i){
answer[i]=path[m-i][k];
k-=p[answer[i]]-d[answer[i]];
}
std::sort(answer,answer+m);
for(int i=0; i<m; printf(" %d", answer[i++]+1));
printf("\n\n");
}
return 0;
}