状压DP
状压DP
//一维dp:糖果【蓝桥杯省赛】
# include <bits/stdc++.h>
using namespace std;
const int MAXN=1<<21;
int dp[MAXN],s[110];
int main()
{
    memset(dp,-1,sizeof(dp));
    int N,M,K; scanf("%d%d%d",&N,&M,&K);
    for(int i=1;i<=N;++i){
        int ss=0,t=0;
        for(int j=1;j<=K;++j){
            scanf("%d",&t);
            ss|=(1<<(t-1));   //将每一包糖果转化为可表述
        }
        s[i]=ss;
        //cout<<"ss="<<ss<<endl;
        dp[ss]=1;
    }
    for(int i=1;i<=N;++i){
        for(int j=0;j<(1<<M);++j){   //对每一个现有状态加上一包
            if(dp[j]==-1) continue;
            if(dp[j|s[i]]==-1) dp[j|s[i]]=dp[j]+dp[s[i]];
            else dp[j|s[i]]=min(dp[j|s[i]],dp[j]+dp[s[i]]);
        }
    }
    printf("%d\n",dp[(1<<M)-1]);
    return 0;
}
//二维dp:Mondriaan's Dream
# include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int N,M;
int in[1<<12];
LL f[20][1<<12];
int main()
{
    while(~scanf("%d%d",&N,&M)){
        if(N==0&&M==0) break;
        memset(in,0,sizeof(in));
        memset(f,0,sizeof(f));
        for(int i=0;i<(1<<M);++i){ //0 ~ 2^M-1 每一段连续的0都是偶数个
            int odd=0,cnt=0;
            for(int j=0;j<M;++j){
                if((i>>j)&1) odd|=cnt,cnt=0;
                else cnt^=1;
            }
            in[i]=odd|cnt?0:1;
        }
        f[0][0]=1;
        for(int i=1;i<=N;++i){
            for(int j=0;j<(1<<M);++j){
                for(int k=0;k<(1<<M);++k){ //将条件化为位运算
                    if((j&k)==0&&in[k|j]) f[i][k]+=f[i-1][j];
                }
            }
        }
        printf("%lld\n",f[N][0]);
    }
    return 0;
}
//方格取数
# include <bits/stdc++.h>
using namespace std;
int G[20][20];
int f[20][1<<19];
int is[1<<20];
int N;
int cal(int  
                    
                     
                    
                