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;
}

posted on 2024-04-11 13:58  WHUStar  阅读(5)  评论(0编辑  收藏  举报