whu1608 Calculation
2016-04-10 16:43
274 查看
链接:http://acm.whu.edu.cn/land/problem/detail?problem_id=1608&contest_id=16
题意:给定n个数,将这n个数随意划分为若干个集合,求一次划分后最大的满足条件的集合个数,条件为:将集合内所有的元素进行+-两种运算后结果为s。
分析:看到题面和数据规模都很容易看出是状压DP。我们枚举集合是2^n,然后还有快速判断一个集合是否能满足条件,而且集合的dp要靠子集来传递。很容易想到是二进制集合枚举子集那种3^n的方法(不熟的可以参考《算法竞赛入门经典训练指南》P69例题29)。判断一个集合是否满足条件也只要枚举子集来当做要减去的数的集合即可。详见代码。O(t*3^n)
代码:
#include<map> #include<set> #include<cmath> #include<queue> #include<bitset> #include<math.h> #include<cstdio> #include<vector> #include<string> #include<cstring> #include<iostream> #include<algorithm> #pragma comment(linker, "/STACK:102400000,102400000") using namespace std; const int N=100010; const int MAX=151; const int mod=100000000; const int MOD1=100000007; const int MOD2=100000009; const double EPS=0.00000001; typedef long long ll; const ll MOD=1000000009; const ll INF=10000000010; typedef double db; typedef unsigned long long ull; int a[20],e[20],f[17000],g[17000],bo[17000]; int main() { int i,j,n,s,t,w,ans; e[0]=1; for (i=1;i<20;i++) e[i]=e[i-1]*2; scanf("%d", &t); while (t--) { scanf("%d%d", &n, &s); for (i=e -1;i>=0;i--) f[i]=g[i]=bo[i]=0; for (i=0;i<n;i++) { scanf("%d", &a[i]); for (j=e -1;j;j--) if (j&e[i]) g[j]+=a[i]; } for (i=e -1;i;i--) { if (g[i]==s) { bo[i]=1;continue ; } for (j=i;j;j=(j-1)&i) if (g[i]-g[j]-g[j]==s) { bo[i]=1;break ; } } ans=0; for (i=1;i<e ;i++) { if (bo[i]) f[i]=1; for (j=i;j;j=(j-1)&i) if (bo[j]) f[i]=max(f[i],f[i^j]+1); ans=max(ans,f[i]); } printf("%d\n", ans); } return 0; }
相关文章推荐
- 49、java四种内部类详解
- < < < 2013年国家集训队作业 > > >
- Nio
- Oracle 创建普通用户,并赋予权限
- 安卓学习笔记之json
- c语言学习笔记(一)
- HTTP 1.1与HTTP 1.0的比较
- 【剑指offer系列】 连续子数组的最大和___31
- 考研(2)
- 剑指offe系列之6:旋转数组的最小值
- PS里建立工作路径对话框中的“容差”是干什么的?
- NYOJ:题目113 字符串替换
- 图标对文本对齐的影响
- Android属性动画完全解析(下),Interpolator和ViewPropertyAnimator的用法
- singleton和prototype的区别
- 算法之全排列
- 重学数据结构系列之——图论算法之FloodFill 算法
- 接口和抽象类的区别是什么
- 理解webservice SOAP WSDL
- SparkML之假设性检验(一)