直接切入正题吧,我觉得这个题和我这里的http://blog.csdn.net/good_night_sion_/article/details/53426599第16道动态规划是类似的。
我想的状态表示是dp[i][j][k]表示前i个人选了j个差为k的状态是不是可达,给每一个人记录编号,然后按照控方+辩方分数之和从小到大排序,最后找解的之后贪心优先选择后面的,好吧,在写完这句话的这一刻我就意识到我的写法错了。
AC的写法是定义状态dp[i][k]表示选了i个人差为k时的最大控方+辩方分数
因此状态转移方程就是dp[i+1][k+第j个人控方分-第j个人辩方分]=dp[i][k]+第j个人控方分+第j个人辩方分,条件是第j个人没有使用过
然后要重构解的话,要定义一个额外的数组record表示这个状态是从哪里转移过来的,当然我的意思不是只要重构解就要定义一个新数组
代码应该是很好懂的,对了,在POJ上交的话,不能用我的那个for_each语句,需要自己写一个for循环来输出,POJ不支持lambda表达式...
TIPS:judge用于判断状态为i,k的时候第j个人有没有用过,getans用于把人放到ans里面去
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
typedef pair<int,int> pa;
pa arr[205];
vector<int> ans;
int dp[25][805],record[25][805],n,m,a,b,kcase=1;
bool judge(int i,int j,int k);
void getans(int k);
int main(){
while(scanf("%d%d",&n,&m)&&n+m){
for(int i=0;i<n;++i)
scanf("%d%d",&arr[i].first,&arr[i].second);
memset(dp,-1,sizeof dp);
memset(record,-1,sizeof record);
dp[0][m*5<<2]=0;//m*20
for(int i=0;i<m;++i)
for(int k=0;k<=((m*5)<<3);++k)//k<=m*40
if(dp[i][k]!=-1)
for(int j=0;j<n;++j)
if(dp[i][k]+arr[j].first+arr[j].second>dp[i+1][k+arr[j].first-arr[j].second]&&judge(i,j,k))
dp[i+1][k+arr[j].first-arr[j].second]=dp[i][k]+arr[j].first+arr[j].second,record[i+1][k+arr[j].first-arr[j].second]=j;
for(int te=((m*5)<<2),k=0;k<=te;++k)
if(dp[m][te+k]!=-1&&dp[m][te-k]!=-1){
if(k==0)
getans(te);
else
getans((dp[m][te+k]>dp[m][te-k])?te+k:te-k);
break;
}
else if(dp[m][te+k]!=-1){
getans(te+k);
break;
}
else if(dp[m][te-k]!=-1){
getans(te-k);
break;
}
printf("Jury #%d\nBest jury has value %d for prosecution and value %d for defence:\n",kcase++,a,b);
for_each(ans.begin(),ans.end(),[](int k){printf(" %d",k+1);});
printf("\n\n");
ans.clear();
a=b=0;
}
return 0;
}
bool judge(int i,int j,int k){
int te;
while(record[i][k]!=-1){
te=record[i][k];
if(te==j)
return false;
k+=arr[te].second-arr[te].first,--i;
}
return true;
}
void getans(int k){
int i=m,te;
while(record[i][k]!=-1){
ans.push_back(te=record[i][k]);
a+=arr[te].first,b+=arr[te].second;
k+=arr[te].second-arr[te].first,--i;
}
sort(ans.begin(),ans.end());
}