安排公牛

来源:互联网 发布:深濑昌久 鸦 知乎 编辑:程序博客网 时间:2024/04/29 13:57

安排公牛

Description

Fammer Johnson的公牛们非常喜欢打篮球。但它们都不愿意一起打篮球,因为所有公牛都认为其他的牛弱爆了。Fammer Johnson有N头牛(我们把它们编号为1~N)和M个牛棚(我们把它们编号为1~M),这些牛棚就是公牛们的篮球场。但FJ的公牛非常挑剔,它们只会在自己喜欢的牛棚打球,并且都不愿意和其他的牛共享牛棚。
因此安排他的公牛对Famer Johnson来说是一项艰难的任务,他希望得到你的帮助。当然,找到一种方案是容易的,但你的任务是找出一共有多少种方案。
一个方案是一种使得所有公牛都能在它喜欢的牛棚中快乐玩耍,并且没有两只牛共享一个牛棚的安排方式。答案不会超过32位无符号整数范围。

Input

第一行有两个正整数N,M(1<=N,M<=20)。
接下来有N行,第i行的开头有一个正整数P(1<=P<=M),代表第i头牛喜欢的牛棚数量。接下来有P个正整数,即P个牛棚的编号。

Output

输出一行一个正整数,即方案总数。

Sample Input

3 4
2 1 4
2 1 3
2 2 4

Sample Output

4

Source 

POJ 2441

位运算, 动态规划 ,状态压缩

Solution

又是一道状态压缩

首先用一个数组记录i头牛与j号棚之间的喜好关系(bool就行),喜欢为1,不喜欢为0

枚举每一头牛,即对于每一头牛可能的分配方式(其实就是枚举每一种可能的分配方式),然后用当前牛的喜好情况去更新当前枚举的分配方式(普通的位运算实现即可),注意:为了避免重复每一种用来更新的分配方式更新完后就清0,只有它有值时才用来更新

Code

#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <algorithm>#include <cmath>#include <stack>#include <map>#include <vector>#include <queue>#define LL long longusing namespace std;LL n, m, q, a, ans;bool lik[30][30];LL dp[(1 << 20)];int main() {  freopen("examnine.in", "r", stdin);  freopen("examnine.out", "w", stdout);  scanf("%d %d", &n, &m);  for (int i = 1; i <= n; ++i) {    scanf("%d", &q);    for (int j = 1; j <= q; ++j)       scanf("%d", &a), lik[i][a - 1] = 1;  }  dp[0] = 1;  for (int i = 1; i <= n; ++i)    for (int j = (1 << m) - 1; j >= 0; j--) {      if (!dp[j]) continue;      for (int k = 0; k < m; ++k) {if (j & (1 << k)) continue;if (!lik[i][k]) continue;int temp = (j | (1 << k));dp[temp] += dp[j];      }      dp[j] = 0;    }  for (int i = 0; i < (1 << m); ++i) ans += dp[i];  printf("%d\n", ans);  return 0;}

Summary

考试的题,考试的时候写了一个搜索,70分,实在是想不出转移方程

后面参看了一下题解,意识到了些玄学问题,就想出了转移方程,但是还是WA了……

对着数据调了一会儿瞬间发现bug:dp初值都没赋,什么都没有更新,直接输出0

加上dp[0] = 1,就A了

1 0
原创粉丝点击