Codevs 1959 拔河比赛

来源:互联网 发布:穿普拉达的恶魔 知乎 编辑:程序博客网 时间:2024/05/03 16:47

题目:

http://codevs.cn/problem/1959/

题解:

乱搞70:数据水
1.把对应质量赋价值,sum/2最高,向两边递减。
体积为人数,做01。只得70
2.0~sum/2递增赋值,大于sum/2的赋值为0;
cnt=n/2,以cnt和n-cnt为体积分别做01(防止某一组的总重量大于sum/2),取差值小的那组答案输出。也得70
WA的原因
有后效性,当前的选择影响了以后的选择能不能达到最优值
质量和所赋的价值并不是完全成正比的。不是“价值”越高越好
对于01 相同体积内,得到的物品价值和越大越优,无后效型;
对于本题 相同人数,并不是质量越接近sum/2越优,某个更接近sum/2的质量有可能阻碍了以后的最优值选择。
譬如 sum/2=70 现在有质量为20和30两种选择,因为上述赋值,肯定会选择30,
但是下一层循环若有一个质量为50的人,本来可以和20组合,达到最优值,但是由于刚刚的目光短浅选择了30,错过了最优值。

正解DP:(抄题解)
dp[i][j][k]=1/0 表示从前i个人中选了j个人,能否达到k重量

这个状态有一点像
http://blog.csdn.net/loi_lxt/article/details/78124820

dp[i][j][k]=dp[i-1][j][k]|dp[i-1][j-1][k-w[i]];                不选第i个人    选第i个人

最后枚举可能的k值,记录答案;
注意:
二维数组某一维是负数,,,不re,,,wa

数组越界!!!!!

代码:

70分乱搞#include<iostream>#include<cstdio>using namespace std;const int N=100+60;int n,w[N],dp[N],sum,cnt,mp[55000];int main(){    scanf("%d",&n);    for(int i=1;i<=n;i++) scanf("%d",&w[i]),sum+=w[i];    cnt=n/2;    for(int i=1;i<=sum/2;i++) mp[i]=i*3,mp[sum-i]=mp[i];    //for(int i=1;i<=sum;i++) printf("%d ",mp[i]);    for(int i=1;i<=n;i++){        for(int j=cnt;j>=1;j--){            if(mp[dp[j]]<mp[dp[j-1]+w[i]]) dp[j]=dp[j-1]+w[i];        }    }    int ans1=dp[cnt];    int ans2=sum-dp[cnt];    if(ans1>ans2) swap(ans1,ans2);    cout<<ans1<<" "<<ans2<<endl;    return 0;}
AC DP#include<iostream>#include<cstdio>#include<cmath>using namespace std;const int N=100+2;int n;int w[N],dp[N][N*451],sum,ans,minn=1e9+7;;int main(){    scanf("%d",&n);    for(int i=1;i<=n;i++) scanf("%d",&w[i]),sum+=w[i];    dp[0][0]=1;    int cnt=(n+1)/2;    for(int i=1;i<=n;i++)    for(int j=cnt;j>=1;j--)    for(int k=sum;k>=w[i];k--){        dp[j][k]=dp[j][k]|dp[j-1][k-w[i]];    }    for(int k=0;k<=sum;k++){        if(!dp[cnt][k]) continue;        int tmp=k;        if(abs(sum-tmp-tmp)<minn){            minn=abs(sum-tmp-tmp);            ans=tmp;        }    }    int ans2=sum-ans;    if(ans>ans2) swap(ans,ans2);    printf("%d %d",ans,ans2);    return 0;}
原创粉丝点击