zoj 3305
2011-11-22 12:52
274 查看
这两天好多课。。不过还好星期四开始放四天的假,哈哈哈哈~
/* zoj_3305 dp 引用一段别人的解释: 题意: 一个n<=16个元素的集合,给定m<=种备选子集,问最多可划分出多少个不相交的备选子集。 (状态dp+子集枚举) 核心思想是二进制表现。 x = (x - 1) & st 实现了子集遍历 比如 st=1110 1101 & 1110 = 1100 1011 & 1110 = 1010 1001 & 1110 = 1000 0111 & 1110 = 0110 0101 & 1110 = 0100 0011 & 1110 = 0010 0001 & 1110 = 0000 Proecess: 1.本来是想拿来当最大流的题目练的,建图的时候发现好像有点问题。 2.然后百度了一下,发现用最大流做的跟我的思路都差不多,几乎都是拆点啊,超级源连每个配方首元素,超级 汇点连每个配方尾元素。然后中间元素之间再连边建图的。 我怎么看都觉得这样做有问题的,比如一组很简单的数据: 5 4 2 1 2 2 2 3 2 3 4 1 4 基本上那些代码都是输出3,明显是2的。。 3.然后就看到这种很用二进制表现的很巧妙的方法。。几乎完全参考人家的代码过的。。 */ #include <iostream> #include <cstdio> #include <string.h> #define N 1<<16 using namespace std; bool flag ; int dp ; int solve( int ori ) { int i,temp; if( dp[ori]!=-1 ) return dp[ori]; //重复计算很多 dp[ori]=0; //必须,因为下面的if可能进不去 for( i=ori;i!=0;i=(i-1)&ori ) if( flag[i] && dp[ori]<( temp=solve(ori-i)+1 ) ) dp[ori]=temp; return dp[ori]; } int main() { int n,m,k,i,j; while( scanf( "%d%d",&n,&m )!=EOF ) { memset( flag,0,sizeof(flag) ); memset( dp,-1,sizeof(dp) ); while( m-- ) { scanf( "%d",&k ); j=0; while( k-- ) { scanf( "%d",&i ); i=1<<(i-1); j+=i; } flag[j]=1; } printf( "%d\n",solve( (1<<n)-1 ) ); //最里层括号必须 } return 0; }
相关文章推荐
- zoj_3305_最大流
- ZOJ 3305 Get Sauce
- zoj 3305 - Get Sauce
- ZOJ-3305
- (DP) zoj 3305
- ZOJ3305 Get Sauce(最大流)
- ZOJ 3305 Get Sauce(DFS+剪枝)
- ZOJ 3305 集合上的动态规划
- ZOJ 1733 Common Subsequence【DP】
- 逆向并查集(ZOJ 3261)
- ZOJ 3793 First Digit (逗比题)
- ZOJ 3212 K-Nice【】
- zoj 3323 Somali Pirates
- zoj 3656
- ZOJ 3201 树形背包问题
- ZOJ - 2477 dfs [kuangbin带你飞]专题二
- zoj 1889 Ones
- ZOJ 1655 (Dijkstra算法+一点变化)
- ZOJ Problem Set - 1295 Reverse Text
- ZOJ 1403&&HDU 1015 Safecracker【暴力】