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 <iostream>
using namespace std;

const int MOD = 1000000007;
int n, m, c, d, pre = 0, now = 1;
long long dp[2][25][1222];
char g[105][15];

int main() {
	while (~scanf("%d%d%d%d", &n, &m, &c, &d)) {
		int maxs = (1<<m);
		memset(dp[now], 0, sizeof(dp[now]));
		dp[now][0][maxs - 1] = 1;
		for (int i = 0; i < n; i++)
			scanf("%s", g[i]);
  		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				swap(pre, now);
				memset(dp[now], 0, sizeof(dp[now]));
				int tmp = g[i][j] - ‘0‘;
				if (tmp) {
					for (int k = 0; k <= d; k++) {
						for (int s = 0; s < maxs; s++) {
							if (k && (s&1<<j))
								dp[now][k][s] = (dp[now][k][s] + dp[pre][k - 1][s]) % MOD;//放1X1
							if (j && !(s&1<<(j-1)) && (s&1<<j))
								dp[now][k][s|1<<(j-1)] = (dp[now][k][s|1<<(j-1)] + dp[pre][k][s]) % MOD;//横放1X2
  							dp[now][k][s^1<<j] = (dp[now][k][s^1<<j] + dp[pre][k][s]) % MOD;//竖放1X2
						}
    				}
    			}
    			else {
    				for (int k = 0; k <= d; k++) {
    					for (int s = 0; s < maxs; s++) {
    						if ((s&1<<j))
								dp[now][k][s] = (dp[now][k][s] + dp[pre][k][s]) % MOD;//不能放的情况,和放1X1类似
         				}
        			}
       			}
   			}
  		}
  		long long ans = 0;
  		for (int i = c; i <= d; i++)
  			ans = (ans + dp[now][i][maxs - 1]) % MOD;
  		printf("%lld\n", ans);
 	}
	return 0;
}

HDU 4804 Campus Design(插头DP)

时间: 2024-10-29 19:13:32

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

题意: 给出一个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 题

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

【插头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 4949 Light(插头dp、位运算)

比赛的时候没看题,赛后看题觉得比赛看到应该可以敲的,敲了之后发现还真就会卡题.... 因为写完之后,无限TLE... 直到后来用位运算代替了我插头dp常用的decode.encode.shift三个函数以及改改HASH值才勉强过的...7703ms 题意:给一个N*M的01矩阵,每次可以选一个格子进行2种操作,①翻转邻居格子②翻转邻居格子和自己.输出最小的总操作数使得矩阵全为0. 显然每个格子有4种操作(一.不操作:二.①②:三.①:四.②). 一开始写的时候用2位表示一个插头,一位用于表示翻转

HDU 3377 Plan (插头DP,变形)

题意:有一个n*m的矩阵,每个格子中有一个值(可能负值),要从左上角走到右下角,求路径的最大花费. 思路: 除了起点和终点外,其他的点可以走,也可以不走. (2)我用的是括号表示法,所以起始状态为')',即仅有一个右括号,那么到右下角也应该是只有一个右括号.因为,如果碰到()),加粗表示起点的那个右括号,那么合并后变成)##,仍然是右括号,如果是)(),那么合并后变成##),仍然是右括号,相当于延续了.插头每到达一个格子就先将其值给加上,如果要合并的时候,再减掉(因为多算了一次),因此,新括号的

HDU 1964 Pipes (插头DP,变形)

题意:给一个n*m的矩阵,每个格子都是必走的,且无障碍格子,每对格子之间都有一个花费,问哈密顿回路的最小花费. 思路: 这个和Formula1差不多,只是求得是最小花费,这只需要修改一下DP值为花费就行了,主要是在创建新括号,以及延续一个插头的时候花费,因为可能上一个格子有多个状态都可以转移到本格子的同一状态,那么同一个格子中的同一状态的DP值取最小值即可. 1 #include <bits/stdc++.h> 2 #include <iostream> 3 #include &l

插头DP学习

队内没人会插头DP,感觉这个不会不行...所以我还是默默去学了一下, 学了一天,感觉会了一点.对于每一行,一共有j+1个插头,如果是多回路类的题目, 比较简单,可以用1表示有插头,0表示没有插头,这样就可以愉快转移了, 对于当前出来的位置(i,j),与它有关的插头有j-1和j 那么我们可以枚举状态经行转移. 对于单回路的问题....只是了解思想,目前还不会写,太笨了=_= poj 2411 Mondriaan's Dream 题意:用1*2小方块组成n*m矩阵有多少种组成方式 思路:我们从上到下