【算法】状态压缩DP

状态压缩DP是什么?

答:利用位运算(位运算比加减乘除都快!)来记录状态,并实现动态规划。

适用于什么问题?

答:数据规模较小;不能使用简单的算法解决。

例题:

题目描述

糖果店的老板一共有M 种口味的糖果出售。为了方便描述,我们将M种口味编号1~M。
小明希望能品尝到所有口味的糖果。遗憾的是老板并不单独出售糖果,而是K颗一包整包出售。
幸好糖果包装上注明了其中K 颗糖果的口味,所以小明可以在买之前就知道每包内的糖果口味。
给定N 包糖果,请你计算小明最少买几包,就可以品尝到所有口味的糖果。

输入

第一行包含三个整数N、M 和K。
接下来N 行每行K 这整数T1,T2,...,TK,代表一包糖果的口味。
1<=N<=100,1<=M<=20,1<=K<=20,1<=Ti<=M。

输出

一个整数表示答案。如果小明无法品尝所有口味,输出-1。

样例输入 

6 5 3
1 1 2
1 2 3
1 1 3
2 3 5
5 4 2
5 1 2

样例输出

2

数据规模不大,很适合用状态压缩DP。

思路如下:

用二进制的1和0来表示某类糖果的有无。比如按照上面的样例,总共有5种糖果。第二行1 1 2就是00011,第三行1 2 3就是00111,最后一行5 1 2就是10011...

然后我们用dp数组在存储这些状态。

int dp[1<<m];

将其初始化为-1.每读取一行,就将相对应的元素赋值1,代表买一包就能买到这些种类的糖果。

AC代码如下:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 int main() {
 5     int n, m, k,s,ss;
 6     cin >> n >> m >> k;
 7     int dp[1 << 20];
 8     int goods[100];
 9     memset(dp, -1, sizeof(dp));
10     for(int j=0;j<n;j++) {
11         ss = 0;
12         for (int i = 0; i < k; i++) {
13             cin >> s;
14             ss |= (1 << (s - 1));
15         }
16         goods[j] = ss;
17         dp[ss] = 1;
18     }
19     for (int i = 0; i < n; i++) {
20         for (int j = 0; j < (1 << m); j++) {
21             if (dp[j] == -1) continue;
22             if (dp[j | goods[i]] == -1)
23                 dp[j | goods[i]] = dp[j] + dp[goods[i]];
24             else
25                 dp[j | goods[i]] = min(dp[j] + dp[goods[i]], dp[j | goods[i]]);
26         }
27     }
28     cout << dp[(1 << m) - 1];
29 }

 

猜你喜欢

转载自www.cnblogs.com/zyyz1126/p/12377491.html
今日推荐