蓝桥训练·糖果 状态压缩+dfs
糖果店的老板一共有 M
种口味的糖果出售。
为了方便描述,我们将 M
种口味编号 1∼M
。
小明希望能品尝到所有口味的糖果。
遗憾的是老板并不单独出售糖果,而是 K
颗一包整包出售。
幸好糖果包装上注明了其中 K
颗糖果的口味,所以小明可以在买之前就知道每包内的糖果口味。
给定 N
包糖果,请你计算小明最少买几包,就可以品尝到所有口味的糖果。
输入格式
第一行包含三个整数 N,M,K
。
接下来 N
行每行 K 这整数 T1,T2,⋅⋅⋅,TK
,代表一包糖果的口味。
输出格式
一个整数表示答案。
如果小明无法品尝所有口味,输出 −1
。
数据范围
1≤N≤100
,
1≤M,K≤20,
1≤Ti≤M
输入样例:
6 5 3
1 1 2
1 2 3
1 1 3
2 3 5
5 4 2
5 1 2
输出样例:
2
二进制枚举,state表示成2进制 其中1就代表该种策略选的类。该做法先预处理下log2【N】,后面要用到。
还要写一个h函数,来估算目前状态下至少需要多少次数才能选完所有类型的糖果。
#include<iostream>
#include<vector>
using namespace std;
const int N=1<<20,M=22;
vector<int>col[M];
int log22[N];
int n,m,k; int lowbit(int x)
{
return x&-x;
}
int h(int state)
{
int res=0;
for(int i=(1<<m)-1-state;i;i-=lowbit(i))
{
int c=log22[lowbit(i)];//代表目前还没被选中
res++;
for(auto m:col[c])//算出下界,算出最少需要多少行(不准确值)
i&=~m;
}
return res;
}
bool dfs(int depth,int state)
{
if(!depth||h(state)>depth) return state==(1<<m)-1; //看看有没有选满
int t =-1;
for(int i=(1<<m)-1-state;i;i-=lowbit(i))
{
int c=log22[lowbit(i)];//c代表没选的最后一位
if(t==-1||col[c].size()<col[t].size())//选择种类最少的方案
t=c;
}
for(auto mm:col[t])
{
if(dfs(depth-1,state|mm))
return true;
}
return false;
}
int main()
{
cin>>n>>m>>k;
for(int i=0;i<m;i++)
log22[1<<i]=i;
for(int i=0;i<n;i++)
{
int state=0;
for(int j=0;j<k;j++)
{
int c;
cin>>c;
state|=1<<c-1;
}
for(int j=0;j<m;j++)
{
if((state>>j)&1) col[j].push_back(state);
}
}
int depth=0;
while(depth<=m&&!dfs(depth,0))
depth++;
if(depth>m) cout<<-1<<endl;
else cout<<depth<<endl;
return 0;
}