网络上大部分关于poj1015的题解都是假的,原因是poj的数据比较水。
比如以下数据能hack大部分题解
9 6
6 2
16 10
4 9
19 8
17 12
4 7
10 2
2 14
5 18
0 0
正解应该是
Jury #1
Best jury has value 54 for prosecution and value 54 for defence:
1 2 3 4 6 9
uva的数据是加强过的,poj的时限和内存卡的更难受一点
所以同时过了uva和poj才能说过了这道题(或者只是uva
题解:就是把每个可能的终点都找出来的时候,把相应终点的使权值最大的路径全部记录(详情请看代码
这份是我的uva的ac代码,提交到poj上需要把auto改掉而且把maxn,maxm卡的更小一点才不会CE和MLE
#include<stdio.h>
#include<cstring>
typedef long long ll;
using namespace std;
const int maxm = 25;
const int maxn = 205;
const int zero = 25;
const int VAL = 45;
struct node{
int val,sum;
//sum为每个人的权值,val为每个人对被告和原告的好感差
}d[maxn];
struct res{
int x,id,k;//k表示这个答案是否存在,x表示当前答案的权值和,id表示从上一层更新到这一层这个答案所使用的id
res *Next;//记录每个每个可能答案的路径
}dp[maxn][maxm][maxm*VAL+1],*ans;
void output(res *p) {
if(p){//初始化后dp[0][0][0].Next=0;
output(p->Next);
if(p->id) {
printf(" %d", p->id);
}
}
}
int n,m,sum,tt=0,x,y,ans_val;
int main() {
//freopen("123.in","r",stdin);
while(~scanf("%d%d",&n,&m)&&n){
tt++;
for(int i=1;i<=n;++i){
scanf("%d%d",&x,&y);
d[i].val=x-y+zero;//把负号去掉
d[i].sum=x+y;
}
memset(dp,0,sizeof dp);
dp[0][0][0].k=1;
for(int i=1;i<=n;++i){
dp[i][0][0].k=1;//对于每个人都可能是从0开始的第一个陪审团成员
for(int j=1;j<=m;++j){
int mx=j*VAL,pos=d[i].val;
for(int k=0;k<=mx;++k){
dp[i][j][k]=dp[i-1][j][k];//把第i-1个人的状态递推到最后一个
if(k<pos)continue;
res &tmp=dp[i-1][j-1][k-pos],&now=dp[i][j][k];
if(tmp.k&&tmp.x+d[i].sum>=now.x){//是否存在更优解
now.x=tmp.x+d[i].sum;
now.Next=&tmp;//保存父节点记录路径
now.id=i;
now.k=1;
}
}
}
}
int mid=m*zero;
sum=-1;
auto ch=dp[n][m];
for(int i=0;i<=mid;i++){
int l=mid-i,r=mid+i;
if(ch[l].k||ch[r].k){//先保证最接近,然后保证权值和最大
ans_val=(ch[l].x>ch[r].x?-i:i);
sum=(ch[l].x>ch[r].x?ch[l].x:ch[r].x);
ans=(ch[l].x>ch[r].x?&ch[l]:&ch[r]);
}
if(~sum)break;
}
x=(ans_val+sum)/2,y=sum-x;
printf("Jury #%d\nBest jury has value %d for prosecution and value %d for defence:\n",tt,x,y);
output(ans);
puts("\n");
}
}