Acwing 蓝桥杯 1243. 糖果

糖果店的老板一共有 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
重复覆盖模型  迭代式递归 + 估值函数
#include<iostream>
#include<vector>
using namespace std;

int n,m,k,c;
vector<int> col[110];
int log2[1<<20];

int lowbit(int x){   // 返回最低位,如 x = 1010,则返回二进制的10即为十进制的2
    return x & -x;
}

int h(int state){   // 估值函数
    int res = 0;
    for (int i = (1 << m) - 1 - state; i ; i -= lowbit(i)){
        int c = log2[lowbit(i)];   // 最右边一列没有被覆盖的列号
        res++;
        for (auto x:col[c])   // col[c]中1代表的是覆盖了,0代表没覆盖,而i中1代表没覆盖,0代表覆盖了,因此x先取个反
            i = i & ~x;
    }
    return res;
}

bool dfs(int depth,int state){
    if (!depth || h(state) > depth) return state == (1 << m) - 1;  // 1 << m - 1 和(1 << m) - 1 是不同的, 减号的优先级高于移位运算符
    
    int t = -1;
    for (int i = (1 << m) - 1 - state; i; i -= lowbit(i)){  // 减去了state,则state中0、1就互换了,如果某一位是1,则代表的是该列还没有被覆盖
        c = log2[lowbit(i)];      // 获得最右边一列的列号
        if (t == -1 || col[t].size() > col[c].size())  // 先去找被覆盖次数最少的行
            t = c;
    }
    
    for (auto x:col[t])           // for循环枚举能覆盖第t列的每一行x, col[t]中存放的是能填满该列的每一行的state值
        if (dfs(depth - 1,state | x))
            return true;
            
    return false;
}


int main(){
    cin>>n>>m>>k;
    
    for (int i = 0; i < m; ++i) log2[1<<i] = i;   // 方便由1<<m得到是 
    
    for (int i = 0; i < n; ++i){
        int state = 0;
        for (int j = 0; j < k; ++j){      // 记录每一行能覆盖哪些列,用二进制的1表示
           cin>>c;
           state = state | (1 << c - 1);
        }
        
        for (int j = 0; j < m; ++j){      // 一共m种糖果,每一列将能将其覆盖的行的state值加入进去
            if (state >> j & 1)
                col[j].push_back(state);
        }
    }
    
    int depth = 1;    
    while(depth <= m && !dfs(depth,0)) depth++;   // while()就是迭代加深操作
    
    if (depth > m) cout<<-1;
    else cout<<depth;
    
    return 0;
}
发布了423 篇原创文章 · 获赞 38 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/weixin_41514525/article/details/104673824