题解 UVA10032 【Tug of War】
https://www.luogu.com.cn/problem/UVA10032
很特别的 dp,并且有背包思想。
1. 简洁题意:
把 个数分为两堆,一堆中有 个数,另一堆中有其他的数,要求两堆数尽量接近。
### 2. 题目分析(位运算 + 状压)
2. 背景分析:因为 ,且即如果 是偶数,这两个部分均要有 块,如果 是奇数,则必须分为 和 两个部分,则 ,因为 很小,可以考虑状压。
3. 解法内容:我们设计状态 代表它能被几个数拼出来,该数组中存一个二进制数,它的第 位代表 这个数是否能够用 个数拼出来,能则为 ,不能则为 。转移方程即为:
我们只要找到一个能被 个数拼出来的并且最接近所有数的和的一半的数,求出动态规划的 数组后,扫一遍统计答案即可。
4. 参考代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; int T,n,a[105],s,ans1,ans2,te; long long f[100005],t; int main(){ scanf ( "%d" ,&T); while (T--){ scanf ( "%d" ,&n); s=0; //多组数据 memset (f,0, sizeof (f)); //多组数据清空 for ( int i=0;i<n;i++){ scanf ( "%d" ,&a[i]); s+=a[i]; //先求所有数的和 } f[0]=1; t=1ll<<n/2+1; t--; te=0x3f3f3f3f; for ( int i=0;i<n;i++){ for ( int j=s;j>=a[i];j--){ f[j]|=((f[j-a[i]]<<1)&t); //把数值固定在t的范围内(根据题意要求) } } for ( int i=0;i<=s;i++){ if (f[i]&(1ll<<(n/2))) if ( abs (i-(s-i))<te){ //这里是选取相差最小的方案 te= abs ((i<<1)-s); ans1=i; ans2=s-i; } if (ans1>ans2){ swap(ans1,ans2); //保证小的在前面 } } printf ( "%d %d\n" ,ans1,ans2); //输出答案,记得换行 if (T) putchar ( '\n' ); //题目格式要求 } return 0; } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】