hdu 4804 Campus Design 轮廓线dp

题意:

给出一个n*m的01矩阵,其中要求把矩阵里面的1用1*1或1*2的砖块铺满,矩阵里面的0为障碍物,问使用1*1的砖块数>=c && <=d 的方案有多少种。

限制:

1 <= n <= 100; 1 <= m <= 10; 1 <= c <= d <= 20;

思路:

因为 1 <= m <= 10 所以可以采用轮廓线dp,

具体状态解释在代码中说明。

/*hdu 4804 Campus Design 轮廓线dp
  题意:
  给出一个n*m的01矩阵,其中要求把矩阵里面的1用1*1或1*2的砖块铺满,矩阵里面的0为障碍物,问使用1*1的砖块数>=c && <=d 的方案有多少种。
  限制:
  1 <= n <= 100; 1 <= m <= 10; 1 <= c <= d <= 20;
  思路:
  因为 1 <= m <= 10 所以可以采用轮廓线dp,
  具体状态解释在代码中说明。
 */
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define LL __int64
const int MOD=1000000007;
const int N=105;
char mp[N][15];
LL dp[2][25][1030];
void gao(int n,int m,int c,int d){
	int limit=(1<<m);
	//cout<<limit<<endl;
	int now=0,pre=1;
	memset(dp[now],0,sizeof(dp[now]));
	dp[now][0][limit-1]=1;
	for(int i=0;i<n;++i){
		for(int j=0;j<m;++j){
			swap(now,pre);
			memset(dp[now],0,sizeof(dp[now]));
			for(int s=0;s<limit;++s){
				//cout<<mp[i][j]<<"!"<<endl;
				if(mp[i][j]=='1'){
					for(int k=0;k<=d;++k){
						if(s & (1<<j))	//不放砖头
							dp[now][k][s ^ (1<<j)]=(dp[now][k][s ^ (1<<j)]+dp[pre][k][s])%MOD;
						if(s & (1<<j))	//放置1*1
							dp[now][k+1][s]=(dp[now][k+1][s]+dp[pre][k][s])%MOD;
						if(j && !(s & (1<<(j-1))) && (s & (1<<j))) //横放1*2
							dp[now][k][s | (1<<(j-1))]=(dp[now][k][s | (1<<(j-1))] + dp[pre][k][s])%MOD;
						if(i && !(s & (1<<j)))	//竖放1*2
							dp[now][k][s ^ (1<<j)]=(dp[now][k][s ^ (1<<j)]+dp[pre][k][s])%MOD;
					}
				}
				else{
					for(int k=0;k<=d;++k){
						if(s & (1<<j))	//判断障碍物
							dp[now][k][s]=(dp[now][k][s]+dp[pre][k][s])%MOD;
					}
				}
			}
		}
	}
	//cout<<now<<endl;
	LL ans=0;
	for(int i=c;i<=d;++i)
		ans=(ans+dp[now][i][limit-1])%MOD;
	cout<<ans<<endl;
}
int main(){
	int n,m,c,d;
	while(cin>>n>>m>>c>>d){
		for(int i=0;i<n;++i)
			scanf("%s",mp[i]);
		gao(n,m,c,d);
	}
	return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-03 20:06:39

hdu 4804 Campus Design 轮廓线dp的相关文章

hdu 4804 Campus Design(插头dp)

题目链接:hdu 4804 Campus Design 题目大意:有1?2的木块无穷个,要求在给定的图n?m的图上,用1?2和1?1的木块铺满,图上的0表示不需要铺的位置,1表示必须要铺的位置.并且1?1的使用数量必须在c到d之间.求总方案数. 解题思路:和uva11270一样的做法,只是需要多添加一位状态来表示用掉1得个数,以及要对当前位置判断是否为可放. #include <cstdio> #include <cstring> #include <algorithm>

HDU 4804 Campus Design(插头DP)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4804 题意:给定一个图,0是不能放的,然后现在有1X1和1X2方块,最后铺满该图,使得1X1使用次数在C到D之间,1X2次数随便,问有几种放法 思路:插头DP的变形,只要多考虑1X1的情况即可,然后DP多开一维表示使用1X1的个数 代码: #include <stdio.h> #include <string.h> #include <algorithm> #include

【插头DP】HDU 4804 Campus Design

通道:http://acm.hdu.edu.cn/showproblem.php?pid=4804

HDU 4804 Campus Design(经典轮廓线问题扩展)

 题意:给定一个图,0是不能放的,然后现在有1X1和1X2方块,最后铺满该图,使得1X1使用次数在C到D之间,1X2次数随便,问有几种放法. 思路:经典问题多米诺的拓展,状态多开一维表示用了几个1*1砖块即可,注意位运算的优先级. #include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<iostream> #include<algorit

HDU 4804 Campus Design

题目:http://acm.hdu.edu.cn/showproblem.php?pid=4804 题意:给你一个n*m的棋盘,让你用1x1和1x2的方块填满它,棋盘有些地方不能放方块,1x1的方块使用有限制,问一共有多少种方法填满 dp多开一维存放1x1的个数,之后就是正常的插头dp思路 #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<cm

hdu 5766 Filling 轮廓线dp burnside

Filling 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5766 Description The board is a rectangle of unit cells with N rows and N columns. At first, cells are empty. ?? has infinite blocks with the size of 2*2. ?? can put blocks in the board as long

2013 ACM-ICPC亚洲区域赛南京站C题 题解 轮廓线DP

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4804 题目大意 给你一个 \(n \times m\) 的矩形区域.你需要用 \(1 \times 1\) 和 \(1 \times 2\) 的砖块铺满这个区域,且满足如下要求: 所有的砖块可以竖着放或横着放: 砖角要放在格点上: \(1 \times 1\) 的砖不能少于 \(C\) 块也不能多于 \(D\) 块, \(1 \times 2\) 的砖没有数量限制. 有些方格在一开始就已经被填充了,

hdu 3555 Bomb(数位dp)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3555 题目大意:就是给你一个数n,判断从0到n有多少个数含有数字49...... 是不是觉得跟hdu2089很相似呀... 思路:跟hdu2089一样的,注意给出的数比较大,所以这儿用__int64  .... code: #include<cstdio> #include<iostream> #include<cstring> #include<algorithm&

HDU 1231 最大连续子序列 DP题解

典型的DP题目,增加一个额外要求,输出子序列的开始和结尾的数值. 增加一个记录方法,nothing special. 记录最终ans的时候,同时记录开始和结尾下标: 更新当前最大值sum的时候,更新开始节点. const int MAX_N = 10001; long long arr[MAX_N]; int N, sta, end; long long getMaxSubs() { long long sum = 0, ans = LLONG_MIN; int ts = 0; for (int