Codeforces Gym 221682 W Grid Coloring(DP)

Problem W — limit 1 second
                                                                                     Grid Coloring
You have an m-by-n grid of squares that you wish to color. You may color each square either red
or blue, subject to the following constraints:
• Every square must be colored.
• Colors of some squares are already decided (red or blue), and cannot be changed.
• For each blue square, all squares in the rectangle from the top left of the grid to that square
must also be blue.
Given these constraints, how many distinct colorings of the grid are there? The grid cannot be

rotated.


Input
The first line of input consists of two space-separated integers m and n (1 ≤ m, n ≤ 30).
Each of the next m lines contains n characters, representing the grid. Character ‘B’ indicates
squares that are already colored blue. Similarly, ‘R’ indicates red squares. Character ‘.’ indicates

squares that are not colored yet.


Output
Print, on a single line, the number of distinct colorings possible.
For the first sample, the 6 ways are:

BB BB BR BB BR BR

BR BR BR BR BR RR

BB BR RR BB BB RR

23

Sample Input and Output

3 2
..
B.

.R                                                     6

7 6
......
.....B
.B..R.
......
...B..
.R....

...R..                                               3


2 2
R.
.B                                                    0


【思路】

题目给定一张可能某些格子已经被涂上蓝色或红色的方格图,要求涂色方案书,涂色必须满足所有蓝色格左上方的格子全涂蓝色,所有红色格右下方的格子全涂红色。

我们可以先处理这个图,把已经上色的蓝色格左上角都涂上,红色格右下角也都涂上,剩下的空白格必定会落在右上到左下之间的区域。容易想到,整张图涂完了以后会形成一条右上到左下的边界。不同的涂色方案意味着这条边界形状不同,我们可以从上到下逐步维护边界的信息以获得最后答案。我们来从上到下、从左到右涂色,假设已经涂到了第i行第j列,设dp[i][j]是第i行第j列涂成蓝色的方案数,那么显然,它涂成红色的情况就被dp[i][j - 1]记录了,所以只考虑把空白格涂为蓝色就够了,因其上面的也只能是第j列到第m列是蓝色的,于是可得转移方程:dp[i][j] = sum(dp[i - 1][k]),其中j <= k <= m。

注意唯有含空格的行才能被涂色,若空格早被分割成右上和左下两块,我们就拿最后一个格记录一下上一行的情况就好。初始时,第一个含有空格的行的被更新的格赋值为1,最后由下而上第一个非零行的和即是答案。

有个坑点,若题目给的图本身便不合法,输出0,若给的图已经被合法地涂满了,输出1


【代码】

//************************************************************************
// File Name: W.cpp
// Author: Shili_Xu
// E-Mail: [email protected] 
// Created Time: 2018年03月21日 星期三 16时59分33秒
//************************************************************************

#include 
#include 
#include 
using namespace std;

const int MAXN = 35;

int n, m;
char gr[MAXN][MAXN];
int g[MAXN][MAXN];
unsigned long long dp[MAXN][MAXN];

int main()
{
	scanf("%d %d", &n, &m);
	char s[MAXN];
	for (int i = 1; i <= n; i++) {
		scanf("%s", s + 1);
		for (int j = 1; j <= m; j++) gr[i][j] = s[j];
	}
	bool flag = true;
	memset(g, 0, sizeof(g));
	for (int i = 1; i <= n && flag; i++) {
		for (int j = 1; j <= m && flag; j++) {
			if (gr[i][j] == 'B') {
				for (int l = 1; l <= i; l++)
					for (int c = 1; c <= j; c++) g[l][c] = 1;
			}
			if (gr[i][j] == 'R') {
				for (int l = i; l <= n; l++)
					for (int c = j; c <= m; c++) {
						if (gr[l][c] == 'B') flag = false;
						g[l][c] = 2;
					}
			}
		}
	}
	if (!flag) {
		printf("0");
		return 0;
	}
	memset(dp, 0, sizeof(dp));
	for (int i = 1; i <= n; i++) {
		int st = -1, ed;
		for (int j = 1; j <= m; j++) {
			if (!g[i][j] && st == -1) st = j - 1;
			if (st != -1)  {
				if (g[i][j]) {
					ed = j - 1;
					break;
				}
				if (j == m) ed = j;
			}
		}
		if (st != -1) {
			for (int j = st; j <= ed; j++) {
				for (int k = j; k <= m; k++) dp[i][j] += dp[i - 1][k];
				if (!dp[i][j]) dp[i][j] = 1;
			}
		}
		else {
			for (int j = 0; j <= m; j++) dp[i][m] += dp[i - 1][j];
		}
	}
	unsigned long long ans = 0;
	for (int l = n; l >= 1; l--) {
		for (int i = 0; i <= m; i++) ans += dp[l][i];
		if (ans) break;
	}
	printf("%llu", (ans > 0 ? ans : 1));
	return 0;
}

你可能感兴趣的:(动态规划)