题目:
题解:
乱搞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.youkuaiyun.com/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;
}