题目描述:
小明喜欢的游戏最近推出了一个关于游戏卡牌的活动,只有能够收集全部种类的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; }