洛谷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循环内的判断条件!注意各运算的优先级!!!!