zoukankan      html  css  js  c++  java
  • poj_2441 状态压缩dp

    题目大意

        N头牛,M个谷仓,每个牛c都有它喜欢的若干个谷仓,现在要将这N头牛安排进谷仓,使得每个牛都位于它喜欢的谷仓,而每个谷仓只能有一头牛。求安排的方案总数。N, M <= 20

    题目分析

        将M个谷仓视为一个整数的M个位,位i为1表示谷仓i被牛占用,否则表示谷仓i没有被牛占用。用状态 dp[i][j] 表示前i头牛安排进谷仓,使得谷仓占用情况形成整数j,所有的方案总数,那么有递推公式: 
    dp[i+1][j | 1 << k] = dp[i+1][j | 1 << k] + dp[i][j],其中j的第k位为0(放置两头牛都占用谷仓k),且k为第i+1头牛喜欢的某个谷仓。 
        由于dp[i+1][...]只和dp[i][...]有关,因此可以使用循环数组进行状态压缩。dp[i&1][...]表示前i头牛的情况,dp[(i-1)&1][...]表示前i-1头牛的情况。

    实现(c++)

    #include <iostream>
    #include<stdio.h>
    #include <vector>
    #include <algorithm>
    using namespace std;
    #define MAX_N 22
    vector<int> gCowLikesBarn[MAX_N]; //存放牛i 喜欢的barns
    //不超过20头牛,有牛位于barn k中,则第k位置为1,则用一个整数表示barn的使用情况。 不超过 1 << 22
    //dp[i][j] 表示前i头牛,barn的占用情况构成数字j,则总的情形个数,则有递推公式
    //dp[i+1][j | 1 << k] = dp[i+1][j | 1 << k] + dp[i][j],其中 j的二进制第k位上为0,否则存在重复,
    //且k为第i+1头牛的一个喜欢的barn号
    
    //dp[i+1][...] 只和 dp[i][...]有关,因此考虑使用滚动数组,优化空间。
    int dp[2][1 << MAX_N];	 
    
    int main(){
    	int n, m;
    	scanf("%d %d", &n, &m);
    	for (int i = 1; i <= n; i++){
    		int p;
    		gCowLikesBarn[i].clear();
    		scanf("%d", &p);
    		for (int j = 1; j <= p; j++){
    			int barn;
    			scanf("%d", &barn);
    			gCowLikesBarn[i].push_back(barn - 1);
    		}
    	}
    	dp[0][0] = 1;
    	for (int i = 1; i <= n; i++){
    		memset(dp[i & 1], 0, sizeof(dp[i & 1])); //滚动数组的当前行(共两行)
    		for (int j = 0; j < (1 << m); j++){
    			if (dp[(i - 1) & 1][j] == 0) //如果前i-1头牛所在的barn构成j的方案总数为0,则j和第i头牛再构成的方案 不合法!
    				continue;
    
    			for (int k = 0; k < gCowLikesBarn[i].size(); k++){ //dp[i+1][j | 1 << k] = dp[i+1][j | 1 << k] + dp[i][j]
    				if (((j >> gCowLikesBarn[i][k]) & 1) == 0){ //不能重复有牛
    					dp[i & 1][j | (1 << gCowLikesBarn[i][k])] += dp[(i - 1) & 1][j];
    				}
    			}
    		}
    	}
    	int count = 0;
    	//此时的dp[i][j]中存放了 n头牛所在的barn构成j的方案总数,全部加和
    	for (int i = 0; i < (1 << m); i++){
    		count += dp[n & 1][i];
    	}
    	printf("%d
    ", count);
    	return 0;
    }
    
  • 相关阅读:
    前端js实现复制功能
    vue中流文件下载
    vuex的module简单使用
    vuex及其辅助函数简单使用
    element中合并单元格操作
    js保留小数并四舍五入方法封装
    数组的基本属性和方法
    数组的深复制、扁平化、排序及去重相关方法
    js基本数据类型及数组对象判断
    for/in 语句用于循环对象属性
  • 原文地址:https://www.cnblogs.com/gtarcoder/p/4909425.html
Copyright © 2011-2022 走看看