POJ 1015 动态规划
找准状态 然后就是考研代码能力了。
给你n,m,让你在n个人里找m个人,使这m个人的两数之差最小,如有多解就输出最大和的那个。
dp[j][k]表示挑选j个人且差为k时的最大和。因为数据不大这样搞又简单又方便。
状态转移自然是:上一个点如果可以到达,就对这个点扫所有的已知数据,如果这个点没有出现过并且加上差之后还大,就是可转移的。
没有出现过用path[j][k]记录上一个最优解。
然后复杂度是赤裸裸的n^4............
感觉有点像当年不会写母函数然后做那个天平平衡那种类型的感觉,转移起来还是挺简单的。
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
int dp[30][1000];
int path[30][1000];
int P[300],D[300];
int Ans[30];
int icase=0;
int main()
{
int n,m;
while (scanf ("%d%d",&n,&m)&&n&&m)
{
for (int i=1; i<=n; i++)
{
scanf ("%d%d",&P[i],&D[i]);
}
memset(dp,-1,sizeof(dp));
memset(path,0,sizeof(path));
int minscore=m*20;
dp[0][minscore]=0;
for (int j=0; j<m; j++)
{
for (int k=0; k<=minscore*2; k++)
{
if (dp[j][k]!=-1)
{
for (int i=1; i<=n; i++)
{
if (dp[j][k]+P[i]+D[i]>dp[j+1][k+P[i]-D[i]])
{
int t1=j,t2=k;
t1=j;
t2=k;
while (t1>0&&path[t1][t2]!=i)
{
t2-=P[path[t1][t2]]-D[path[t1][t2]];
t1--;
}
if (t1==0)
{
dp[j+1][k+P[i]-D[i]]=dp[j][k]+P[i]+D[i];
path[j+1][k+P[i]-D[i]]=i;
}
}
}
}
}
}
int zhong=minscore;
int pian=0;
int pos;
while (dp[m][zhong+pian]==-1&&dp[m][zhong-pian]==-1) pian++;
if (dp[m][zhong+pian]>dp[m][zhong-pian]) pos=zhong+pian;
else pos=zhong-pian;
printf ("Jury #%d\n",++icase);
printf ("Best jury has value %d for prosecution and value %d for defence:\n",(dp[m][pos]+pos-minscore)/2,(dp[m][pos]-pos+minscore)/2);
int top=0,t1=m,t2=pos;
while (t1>0)
{
Ans[top++]=path[t1][t2];
t2-=P[path[t1][t2]]-D[path[t1][t2]];
t1--;
}
sort(Ans,Ans+top);
int flag=1;
for (int i=0; i<top; i++)
{
if (flag)flag=0;
else printf (" ");
printf ("%d",Ans[i]);
}
printf ("\n\n");
}
return 0;
}