洛谷P7859 [COCI2015-2016#2] GEPPETTO,主要使用了dp和状压
time limit per test:1 second
memory limit per test:64.00MB
input:standard input
output:standard output
题目描述
Geppetto 开了一家披萨店,他正在努力做出全市最好的披萨。
Geppetto 用 N 种原材料做比萨,每种原材料只有一个。原材料标号为 1 到 N。做披萨很简单,只要把原材料混合好然后放进烤箱里烤一烤就行了。但Geppetto 发现一共有 M 对原材料是冲突的,如果一对冲突的原材料混合在一份披萨里,这份披萨就会变得十分难吃。这给他带来了额外的麻烦。
Geppetto 想知道他最多能做多少种不同的比萨。如果一份比萨上有编号为 i 的原材料,而另一份比萨上没有,那么这两份比萨就是不同的。
输入格式
第一行两个整数 ,N,M,分别表示原材料总数和冲突总数。
接下来 M 行,每行两个整数 ,xi,yi ,表示一对冲突中两种原材料的编号。
输出格式
一行一个整数,表示 Geppetto 最多能做多少种披萨。
SAMPLES
input1
3 2
1 2
2 3
output1
5input2
3 0output2
8input3
3 3
1 2
1 3
2 3
output3
4解题过程
思路:基本过程就是从几个放东西的盒子中取东西,与高中的概率题差不多。注意:可以一个也不取,条件允许的话也可以全取。其中高中的组合数公式Cn0+Cn1+Cn2+…+Cnn=2^n(这里因为还不太熟练用latax,就这样写的)。所以所有情况一共有2 ^n个,也就是1<<n.
代码实现
#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define dbug(x) cout << #x << '=' << x << endl
const int N = 400 + 10;
typedef long long ll;
int a[N];
int main()
{
int n, m;
cin >> n >> m;
for (int i = 1; i <= m; i++)
{
int l, r;
cin >> l >> r;
l--, r--;
a[i] = (1 << l) | (1 << r);
}
int ans = 0;
for (int i = 0; i < (1 << n); i++)
{
//逐个比较从0到n的二进制的数,排除掉a[]里的数
int flag = 1;
for (int j = 1; j <= m; j++)
{
if ((i & a[j]) == a[j])
//i&a[j]==a[j]说明i==a[j]
{
flag = 0;
break;
}
//如果没有查询到a数组的数,则该方法可行,ans加一
}
ans += flag;
}
cout << ans << endl;
}
代码解释
- 这里是把所有情况从0到n用二进制比较了一遍,0|10=11,也就是在a[i]=11时不可以。
- 第一个for循环中用的或运算:两个位上的数都为0时结果才为0;
- 对于a[]数组,1<<L=“110^L",1<<R="110 ^R”,两个二进制数进行或运算就得到一个含2个1的二进制数,a[]数组用于储存取的两个数或运算的结果。
- 第二个for循环了2^n次(1<<n),来依次比较从0到2 ^n的二进制数与a[]是否有重叠,没有的话ans结果就+1,有的话就不加。
总结
将进行的过程转换成二进制数的位运算,依靠0和1来表示状态,再来检查状态。位运算低于比较运算(大于小于等于)低于加减乘除幂运算,第二个for循环内的判断条件!注意各运算的优先级!!!!
文章介绍了如何通过二进制位运算和动态规划解决一个关于披萨店和冲突原料的问题,计算在限制条件下的披萨种类数。
589





