把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

qzezoj 1337 拔河

今天的\(ACM\)模拟赛,最后一道题让我们抓耳挠腮了好长时间。这道题看似能贪心(\(50\)分),又好像能搜索(\(50\)分),其实就是\(dp\),一道\(01\)背包的变体,问题中一个人要么到一边,要么到另一边。这不就是\(01\)背包嘛!不过还要控制人数。
下面有一个在\(ACM\)上过的,但是被民间数据hank掉的:

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n,sum;
    while(~scanf("%d",&n)){
        sum=0;
        int a[117];
        int xc[50017]={0};
        for(int i=1;i<=n;i++){
            cin>>a[i];
            sum+=a[i];
        }
        for(int i=1;i<=n;i++){
            for(int j=sum/2;j>=a[i];j--){
                xc[j]=max(xc[j],xc[j-a[i]]+a[i]);
            }
        }
        cout<<xc[sum/2]<<" "<<sum-xc[sum/2]<<endl;
    }
    return 0;
}

\(hank\)数据:

4
10
20
500
600

输出:

520 610

而他的输出却是

530 600

这是因为他没控制人数!
下面是控制人数的\(AC\)代码(虽然慢,但稳妥):

#include<bits/stdc++.h>
using namespace std;
int n,f[51][45000],ans,tot,a[514];
bool cmp(int a,int b) {
return a<b;
}
int main() {
while(scanf("%d",&n)!=EOF) {
tot=ans=0;
memset(f,0,sizeof(f));
for(int i=1; i<=n; i++) scanf("%d",&a[i]),ans+=a[i];
f[0][0]=1;
for(int i=1; i<=n/2; i++) {
for(int j=ans/2; j>=0; j--) {
if(f[i-1][j]) {
for(int k=1; k<=n; k++) {
f[i][j+a[k]]=1;
}
    }
}
}
for(int i=ans/2; i<=ans; i++) {
if(f[n/2][i]) {
tot=i;
break;
}
}
printf("%d %d\n",min(tot,ans-tot),max(tot,ans-tot));
}
return 0;
}
posted @ 2020-03-18 11:22  275307894a  阅读(32)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end