POJ2441--Arrange the Bulls(状态压缩。)

题目大意:有N头牛,M个谷仓。每头牛都有自己喜欢呆的谷仓。每个谷仓只能安排一头牛。问一共有多少种分法

思路:

我们用 dp[i][j] 来代表 前 i 头牛,j 的状态,有多少种放法。

dp[i][j] = dp[i][j] + dp[i-1][k]  k 属于 1 ~ (1 << m)-1 

我们可以发现, 第 i 状态只和 i-1  的状态有关 ,所以可以滚动数组。

最后我们统计答案的时候, 枚举 1 到 (1 << m) -1 每一种状态,不断加和,统计有多少种放法。

 

更新答案的时候,直接加起来。是因为当前的状态有可能已经有放法了。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <algorithm>
#define mem(x,v) memset(x,v,sizeof(x)) 
#define go(i,a,b)  for (int i = a; i <= b; i++)
#define og(i,a,b)  for (int i = a; i >= b; i--)
using namespace std;
typedef long long LL;
const double EPS = 1e-10;
const int INF = 0x3f3f3f3f;
bool mp[25][25];
int dp[2][1 << 21];

int main(){
	int ans = 0,n,m;
	scanf("%d%d",&n,&m);
	go(i,1,n){
		int op,x;
		scanf("%d",&op);
		go(j,1,op) scanf("%d",&x),mp[i][x] = 1;
	}
	mem(dp,0); dp[0][0] = 1;
	go(i,1,n){
		int now = i%2;
		int pre = (i - 1) % 2;
		go(j,0,(1 << m)-1){
			if (dp[pre][j]){//必须是前面的状态存在值,就是有马。
				go(k,1,m){
					if (mp[i][k] && !(j&(1<<(k-1)))){ //可以放这个马,正好这个位置还没有放。
						dp[now][j | (1 <<(k-1))] += dp[pre][j];
					}
				}
			}
		}
	    mem(dp[pre],0);
	}
	go(i,0,(1<<m)-1) //每个状态有可能有不同放法。
	ans += dp[n%2][i];
	printf("%d\n",ans);
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值