您的位置:首页 > 其它

Tug of War

2013-09-11 20:24 260 查看

Tug of War

        典型的01背包动态规划。其实鄙人是动态规划小菜鸟,只能是说知道有这么回事。但是比赛时这题没有做出来还是很郁闷。因为我的思想完全没有错,输出的数字我也想不到哪里还会错,一直WRONG ANSWER。我一直都觉得,要是我只是格式不对,会给我个PE,没想到这是送到UVA用虚拟账户测的,UVA里面没有PE的概念,只要答案和参考文件不是完全一样,就是WA。

         有n个人,要分成2组,每个人有一个体重,要求两组人的总体重尽可能的接近。两个组的人数只差不得超过1.分别输出两个组分好后,人员总体重。总体重小的那个组先输出,中间隔一个空格。两组测试数据的测试结果之间有换行。

       也就意味着出了最后一组外,其他的每组数据后面有换行。或说,出了第一组数据之外,其他数据数据的前面有空间(我就是错在这里,看题目不够仔细)。要是人的总数n是偶数,那么每组的人数都必须是n/2,否则,一组是n/2取整,一组是n/2取整后加1.

        这个题目和刚入门的动归不一样,他求的不是最大值,也不是最小值,是最接近值。也就是说,要的是存在性。所以,我们可以求出在使用一定人数的情况下,可以组成的体重的总数的各种值。最后再把人数一定,找出最接近中间值的那个数即可。

        动态转移方程: if(dp[j][k]) dp[j+1][k+wei[i]]=true;

       dp[j][k]表示从所有人里面选出j个人能拼成k的总体重;

        在j个人能拼出的总体重可以等于k时,那么我们加入第i个人,我们的总人数就是j+1了,这时候拼出的总体重就是k+wei[i]了;

      在处理的时候,我们必须从后面往前面搜索k。否则,我们本次处理的前面得出的数据变化会影响到后面的处理。

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
bool dp[55][22550];  //比较大,要放在堆里面,否则会爆栈
int wei[102];  //所有人的体重
int main()
{
int t;
int n;
int sum;
int i,j,k;
int f=0;
cin>>t;
while(t--)
{
sum=0;
cin>>n;
for(i=0; i<n; i++)cin>>wei[i],sum+=wei[i];
memset(dp,false,sizeof(dp));

 dp[0][0]=true;   //0个人的时候,总体重一定是0
 for(i=0; i<n; i++)   //动归打表
for(j=n/2; j>=0; j--)
for(k=sum/2-wei[i]; k>=0; k--)
if(dp[j][k])
dp[j+1][k+wei[i]]=true;
int max;
for(i=sum/2; i>=0; i--)  //其中一组的总人数可以是n/2,总体重一定不大于sum/2
if(dp[n/2][i])
{
max=i;
break;
}
if(n%2!=0)    //要是n为奇数,则该组人的总数可以为n/2+1
for(i=sum/2; i>=0; i--)
if(dp[n/2+1][i])
{
if(i>max)max=i;  //求的是,在该组总体重不大于所有人的总体重的情况下,该组总体重的最大值(最接近sum/2)
break;
}
if(f)cout<<endl;   //案例间有空格
cout<<max<<" "<<sum-max<<endl;
f=1;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息