P8687 [蓝桥杯 2019 省 A] 糖果
题面:
链接:https://www.luogu.com.cn/problem/P8687
总的思路就是状态压缩:
如m为4时,1101代表有1,3,4口味的糖果。
然后状态转移用dp[i]:i是口味,某几种口味的集合。
用tg[i]存每包的糖果种类,然后重点在于转移方程
#include<iostream>
#include<vector>
#include<algorithm>
#include<math.h>
#include<sstream>
#include<string>
#include<string.h>
#include<iomanip>
#include<stdlib.h>
#include<map>
#include<queue>
#include<limits.h>
#include<climits>
#include<fstream>
#include<stack>
typedef long long ll;
using namespace std;
int n, m, k;
ll dp[1 << 20];
ll tg[110];
bool can[30];
int num = 0;
int main()
{
memset(dp, 0x3f3f3f, sizeof(dp));
memset(tg, 0, sizeof(tg));
cin >> n >> m >> k;
for (int i = 0; i < n; i++)
{
bool vis[30]; memset(vis, 0, sizeof(vis));
for (int j = 0; j < k; j++)
{
ll xx; cin >> xx;
if (!vis[xx])
{
vis[xx] = 1;
tg[i] |= (1 << (xx - 1));
}
if (!can[xx])
{
can[xx] = 1;
num++;
}
}
dp[tg[i]] = 1;
}
if (num < m) { cout << -1; return 0; }
for (int s = 1; s < (1 << m); s++)
{
for (int i = 0; i < n; i++)
dp[s | tg[i]] = min(dp[s | tg[i]], dp[s] + 1);
//s:遍历所有的糖果组合
//i:遍历背包中的糖果组合
//s | tg[i]指的是某种合并后的组合,然后这个的值是它和“状态s下所需糖果包数的最小值+1包”的最小值
}
cout << dp[(1 << m) - 1];//dp[1111....111]的值:(1<<m)-1;
return 0;
}