经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » 编程经验 » 查看文章
Luogu-P1450 [HAOI2008]硬币购物-完全背包+容斥定理
来源:cnblogs  作者:__Simon  时间:2019/10/8 9:09:55  对本文有异议

Luogu-P1450 [HAOI2008]硬币购物-完全背包+容斥定理


【Problem Description】

【Solution】

上述题目等价于:有\(4\)种物品,每种物品有\(d_i\)个,且每种物品的体积为\(c_i\),问有多少种方法装满容量为\(s\)的背包?可以很容易想到跑多重背包即可,但是发现复杂度为\(O(4V\cdot n)\)。不可行。

题目要求的东西也等价于求以下等式有多少组满足条件的解:
\[ c_1\cdot x_1+c_2\cdot x_2+c_3\cdot x_3+c_4\cdot x_4=s\\且0\le x1\le d_1,\ 0\le x_2\le d_2,\ 0\le x_3\le d_3,\ 0\le x_4\le d_4 \]
如果学过容斥定理的,就可以看出来这是容斥定理的一个模型。

即先不考虑\(x_1,x_2,x_3,x_4\)的上界限制条件,即每种物品有无限多个,那么就可以跑完全背包求得所有的方案数,\(\overline A_1,\overline A_2,\overline A_3,\overline A_4\)分别代表\(0\le x1\le d_1,\ 0\le x_2\le d_2,\ 0\le x_3\le d_3,\ 0\le x_4\le d_4\)的条件,那么我们要求的就是满足\(\overline A_1\cap \overline A_2\cap \overline A_3\cap \overline A_4\)的方案数。有容斥原理公式得:
\[ |\overline A_1\cap \overline A_2\cap \overline A_3\cap\overline A_4 |=|S|-(|A_1|+|A_2|+|A_3|+|A_4|)\\+(|A_1\cap A_2|+|A_1\cap A_3|+|A_1\cap A_4|+|A_2\cap A_3|+|A_2\cap A_4|+|A_3\cap A_4|)\\-(|A_1\cap A_2\cap A_3|+|A_1\cap A_2\cap A_4|+|A_1\cap A_3\cap A_4|+|A_2\cap A_3\cap A_4|)\\+(|A_1\cap A_2\cap A_3\cap A_4)\\]
对于\(|A_1|\),我们知道\(A_1\Leftrightarrow x_1\ge d_1+1\)。所以\(|A_1|\)就表示\(x_1\ge d_1+1,\ x_2,x_3,x_4\ge 0\)时以下等式的解的个数:
\[ c_1\cdot x_1+c_2\cdot x_2+c_3\cdot x_3+c_4\cdot x_4=s\\且x_1\ge d_1+1, x_2,x_3,x_4\ge 0 \]
\(z_1=x_1-(d_1+1),z_2=x_2,z_3=x_3,z_4=x_4\),则原式变为在\(z_1,z_2,z_3,z_4\ge 0\)的条件下,求以下等式解的个数:
\[ c_1\cdot z_1+c_2\cdot z_2+c_3\cdot z_3+c_4\cdot z_4=s-(d_1+1)\\且x_1,x_2,x_3,x_4\ge0 \]
预处理\(10^5\)以内容量为\(i\)方案数\(dp[i]\)。则\(|A_1|=dp[s-(d_1+1)]\)。同理\(|A_i|=dp[s-(d_i+1)]\)

对于\(|A_1\cap A_2|\)等其他子集,也用类似方法转换为完全背包的做法。因为物品数只有\(4\)个,所以用位运算枚举子集,偶加奇数减即可。详细请看代码。复杂度为\(O(4V+2^4\cdot n)\)


【Code】

  1. #include<iostream>
  2. #include<cstring>
  3. #include<cstdio>
  4. #include<algorithm>
  5. using namespace std;
  6. #define int long long
  7. #define INF 0x3f3f3f3f
  8. #define maxn 100005
  9. int dp[maxn];
  10. int c[5],d[5];
  11. void CompleteBack(int V,int vol){ //完全背包
  12. for(int j=vol;j<=V;j++){
  13. dp[j]=dp[j]+dp[j-vol];
  14. }
  15. }
  16. signed main(){
  17. ios::sync_with_stdio(false);
  18. cin.tie(0);
  19. cin>>c[0]>>c[1]>>c[2]>>c[3];
  20. dp[0]=1;
  21. for(int i=0;i<4;i++){
  22. CompleteBack(maxn-5,c[i]);
  23. }
  24. int n;cin>>n;
  25. while(n--){
  26. cin>>d[0]>>d[1]>>d[2]>>d[3];int s;cin>>s;
  27. int ans=0;
  28. for(int i=0;i<(1<<4);i++){ //枚举子集
  29. int sum=s,num=0;
  30. for(int j=0;j<4;j++){
  31. if(i>>j&1){
  32. sum-=c[j]*(d[j]+1); num++;
  33. }
  34. }
  35. if(sum<0) continue;
  36. if(num&1) ans-=dp[sum]; //偶加奇减
  37. else ans+=dp[sum];
  38. }
  39. cout<<ans<<endl;
  40. }
  41. return 0;
  42. }

原文链接:http://www.cnblogs.com/--Simon/p/11627965.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号