用二进制表示每种味道尝了没有,如:一共有五种味道,吃了前三种——00111,吃了五种——11111
每包糖果都可以选或不选
dp(i,j) i代表前i包糖果, j代表所能到达的状态(吃了几种种味)
其实就是01背包问题
dp[i-1][j & (~w[i])]+1 意味着:选这包糖果,从前面未选这包的状态+1包
同时不用担心重复问题
前面:1 2 3
后面:3 4 5
当前:j & (~w[i]) 会把 3, 4,5位上的1化为0,可前面应该是1,2,3位都为1才有的选,但通过这种运算,前面:00001也有的选,00011也有的选,00111也有的选
#include <iostream> #include <cstring> using namespace std; const int N = 110; int n,m,k; int dp[N][1000],w[22]; int main() { cin >> n >> m >> k; int t; for(int i = 1; i <= n; ++i) { for(int j = 1; j <= k; ++j) { cin >> t; w[i] |= (1 << t-1); } } memset(dp,0x3f,sizeof dp); dp[0][0] = 0; int all = (1 << m)-1; for(int i = 1; i <= n; ++i) { for(int j = 0; j <= all; ++j) { dp[i][j] = min(dp[i-1][j],dp[i-1][j & (~w[i])]+1); } } if(dp[n][all] >= 0x3f3f3f3f) cout << -1 << endl; else cout << dp[n][all] << endl; return 0; }
#include <iostream> #include <cstring> using namespace std; const int N = (1<<20)+10; int n,m,k; int dp[N],w[22]; int main() { cin >> n >> m >> k; int t; for(int i = 1; i <= n; ++i) { for(int j = 1; j <= k; ++j) { cin >> t; w[i] |= (1 << t-1); } } memset(dp,0x3f,sizeof dp); dp[0] = 0; int all = (1 << m)-1; for(int i = 1; i <= n; ++i) for(int j = all; j >= 0; j--) { dp[j] = min(dp[j],dp[j & (~w[i])]+1); } if(dp[all] >= 0x3f3f3f3f) cout << -1 << endl; else cout << dp[all] << endl; return 0; }
太晚了题解明早更
#include <iostream> #include <vector> #include <algorithm> using namespace std; const int N = 110, M = 1 << 20; vector<int> col[30]; int log2[M]; int n, m, k; //返回最右边1的位置,比如说:10100返回4(100) 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 = log2[lowbit(i)]; res ++ ; for(auto row : col[c]) i &= ~row; } return res; } bool dfs(int depth, int state) { if(depth == 0 || h(state) > depth) return state == (1 << m) - 1; //优先选择方案数最少的 int t = -1; //减去当前状态就可以得知缺少哪一种糖果,对剩下的糖果取方案数最少的 for(int i = (1 << m) - 1 - state; i; i -= lowbit(i)) { int c = log2[lowbit(i)]; if( t == -1 || col[c].size() < col[t].size()) t = c; } for(int row : col[t]) if(dfs(depth-1,state | row)) return true; return false; } int main() { cin >> n >> m >> k; for(int i = 0; i < m; ++i) log2[1 << i] = i; //log2可以找出每个1的列数 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); } //去掉重复的行 for(int i = 0; i < m; ++i) { sort(col[i].begin(),col[i].end()); col[i].erase(unique(col[i].begin(),col[i].end()),col[i].end()); } int depth = 0; while(depth <= m && !dfs(depth,0)) depth++; if(depth > m) depth = -1; cout << depth << endl; return 0; }