http://poj.org/problem?id=1015
题意:给出几对数,求出|左边总和-右边总和|的值最小,如果存在几对数,需要输出左边总和+右边总和最大的那一个。
考察点:类似背包的巧妙应用;灵活的找到入口;
提交情况:我错了好多次,有几个错误导致。第一个错误我把v[],和sum[],开小了,第2个错误是我把函数表达式写错了,导致越界(见代码);第三个错误:我把x,y的值附为0,导致对出现0,0的情况出错;
思路:一共分为一下几部
1,先寻找子问题,即dp的入口,我总是一直把入口的寻找固定为:已经找到前几个书的最优值,在依次向后退,这是递归思想太严重,(2479题也是这样的犯错),此题的入口为先设定找到第一个人(陪审团的人),同时把他们的差值和总和全部记下,即dp[i][j],i为陪审团的人数,j为他们的差值为j,可以为负,但为了存储,我们应该加上修正值500;dp[i][j]为该状态的最大值;
2,先求出dp[1][j];
3,然后求出dp[i][j],在寻找的过程中,对dp[i][j]中未记录的点(用path[i][j]表示)进行遍历,记录的点跳过;
收获:理解了解决dp题,他们的入口多种多样,此题的入口为陪审团的人数为1,2,3。。。,同时他们的最小值进行枚举;
经验:对有思路的题,我们应该坚决坚持自己写,不管自己的代码有多丑陋,同时在写代码的时候我们应该有自信,同时要考虑全面,不要像我一样,谢了这个代码犹豫了几个小时
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
int dp[35][1000];//i为陪审团的人数,j为枚举的人数为i的差值,dp[i][j]为最大的总和值
int path[35][1000];//path用来记录dp[i][j]当时的路径
int v[350];//用来记录每个点的差值
int sum[350];//用来记录每个点的总和
int a[35];//记录最优值的各点,但后排序并输出;
int main()
{
int ans=0;
int n,m;
int i,j,k;
int x,y;
int t;
int t1,t2;
while(scanf("%d%d",&n,&m),(n&&m))
{
memset(dp,-1,sizeof(dp));
for(i=1;i<=n;i++)
{
scanf("%d%d",&x,&y);
v[i]=x-y;
sum[i]=x+y;
if(dp[1][v[i]+500]<sum[i])
{
dp[1][v[i]+500]=sum[i];
path[1][v[i]+500]=i;
}
}
//求出dp[1][j]的值
for(i=2;i<=m;i++)
{
for(j=50;j<=1000;j++)
{
if(dp[i-1][j]==-1)
continue;
for(k=1;k<=n;k++)
{
t=j;
for(x=i-1;x>=1;x--)
{
// y=dp[x][t];
// if(k==path[x][t-v[y]])
// break;
// t=t-v[y];
//这是刚才写的导致越界
if(k==path[x][t])
break;
t=t-v[path[x][t]];
}
if(x>=1)
continue;
if(dp[i][j+v[k]]<dp[i-1][j]+sum[k])
{
dp[i][j+v[k]]=dp[i-1][j]+sum[k];
path[i][j+v[k]]=k;
}
}
}
}
//求出dp[i][j]的各个值,path[i][j]记录每个dp值的路径
printf("Jury #%d\n",++ans);
for(i=0;i<=500;i++)
{
t1=-i;
t2=i;
y=x=-8;
//y=x=0,刚才写的,导致0的情况出错
if(dp[m][500+i]!=-1)
y=dp[m][500+i];
if(dp[m][500-i]!=-1)
x=dp[m][500-i];
if(x>y)
{
y=x;
t2=t1;
}
if(x+y>=0)
break;
}
printf("Best jury has value %d for prosecution and value %d for defence:\n",(y+t2)/2,(y-t2)/2);
y=500+t2;
t=0;
for(i=m;i>=1;i--)
{
x=path[i][y];
a[t++]=x;
y=y-v[x];
}
sort(a,a+t);
for(i=0;i<t;i++)
printf(" %d",a[i]);
printf("\n");
//按要求输出
}
return 0;
}