题目描述:
小明喜欢的游戏最近推出了一个关于游戏卡牌的活动,只有能够收集全部种类的m张游戏卡牌,就兑换最终大奖;为此小明特意去线下商店购买游戏卡包。假设你是这个商店的老板,你的店里有n包游戏卡牌,每包里有k张游戏卡。现在你已经通过特殊手段得知每个卡包里的卡牌种类,你想知道小明是不是正的欧皇,能通过买最小数量的卡包,来赢得大奖。现在你有一个任务,就是通过已知条件算出购买卡包的最小数量是多少?

毫无疑问,这个题目爆搜肯定会超时的,又因为他的每包卡的数量范围较小,所以我们可以考虑用二进制的方法来表示每种状态,于是---状压dp出来了。
题解:状压dp,首先把dp数组全部置为极大值,对于输入进去的每包卡的都有哪些卡片,我们通过二进制的方法将其表示出来,然后我们再通过枚举处这些卡片的所有组合情况出来,从这里下手进行dp,也就是说:

            for(int j=0;j<(1<<m);j++){
                dp[j|num]=min(dp[j|num],dp[j]+1);
            }

代码:

/*Keep on going Never give up*/
#pragma GCC optimize(3,"Ofast","inline")
#include <bits/stdc++.h>
const int maxn = 310;
const int MaxN = 0x3f3f3f3f;
const int MinN = 0xc0c0c00c;
typedef long long ll;
const int mod = 100000000;
using namespace std;
int dp[1<<18];

int main()
{
    int t;
    cin>>t;
    while(t--){
        int n,m,k;
        cin>>n>>m>>k;
        for(int i=0;i<(1<<m);i++) dp[i]=MaxN;
        dp[0]=0;
        int num;
        for(int i=0;i<n;i++){
            num=0;
            for(int j=0;j<k;j++){
                int x;
                cin>>x;
                num|=(1<<(x-1));
            }
            for(int j=0;j<(1<<m);j++){
                dp[j|num]=min(dp[j|num],dp[j]+1);
            }
        }
        if(dp[(1<<m)-1]==MaxN) cout<<-1<<endl;
        else cout<<dp[(1<<m)-1]<<endl;
    }
    return 0;
}