In order to celebrate the 8th anniversary of ZOJ, LCLL goes to a sauce factory to "Get Sauce". The factory has N kinds of materials. If we combine some of them, we will get a bottle of sauce. LCLL is a sauce genius, he knows about M ways to make the sauce with these materials. Now LCLL wants to get as many bottles of sauce as possible, but he can use each kind of material only once. How many bottles of sauce will LCLL take home at most?
Input
The input file will contain multiple test cases. Each case contains two integers N and M(0 <=N <= 16, 0<= M <=50,000), then there are M lines, each line describe a way to make sauce like this: K a1,a2...aK where K(1<=K<=N) is the number of kinds of materials, ai is a number between[1,N] represents a kind of material this way needs.
Process to the end-of-file.
Output
For each test case print a single line that contains the number of the bottles of sauce LCLL will get at most.
Sample Input
5 3 2 1 2 2 2 3 2 3 4 5 2 1 1 4 1 2 3 4
Sample Output
2 1
Author: CHAO, Jiansong
Source: ZOJ 8th Anniversary Contest
学习到了求一个集合所有子集的方法。。。
j=ret;j;j=(j-1)&ret
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<algorithm> #include<cstdlib> using namespace std; int n,m,dp[(1<<16)+10]; int main() { while(scanf("%d%d",&n,&m)!=EOF) { int ret=(1<<n)-1; memset(dp,0,sizeof(dp)); for(int i=1;i<=m;i++) { int k,x,st=0; scanf("%d",&k); while(k--) { scanf("%d",&x); st=st|(1<<(x-1)); } int ed=ret^st; dp[st]=max(dp[st],1); for(int j=ed;j;j=(j-1)&ed) { if(dp[j]==0) continue; dp[st|j]=max(dp[st|j],dp[j]+1); } } int ans=0; for(int i=1;i<(1<<n);i++) { if(dp[i]>ans) ans=dp[i]; } printf("%d ",ans); } return 0; }