题目描述
小Z在家闲得无聊,摆弄起了围棋棋子。也许是小Z有自虐倾向,他出了个难题给自己,结果竟然把自己难住了。你作为他的朋友,决定帮助他解决难题。
有一个m×n的棋盘,需要在上面摆满黑白棋子。小Z有一个奇怪的规则:如果有两个棋子相邻(上下左右),且一白一黑。则黑的必须在上面(或左边)。黑白棋子都是足够多的。小Z想知道共有多少种不同的摆法(只要略有不同就算一种)。
输入格式
一行,包括两个正整数m和n。
输出格式
一行,包括一个正整数ans,表示共有多少种不同的摆法。
输入样例
2 2
输出样例
6
样例说明
6种摆法分别为:
oo | ×× | ×× | ×o | ×× | × o
oo | ×× | o o | ×o | × o | o o
(×表示黑子,o表示白子)
数据规模
对于50%的数据满足,2≤m,n≤16;
对于100%的数据满足,2≤m,n≤30。
题解
我们设$dp[i][j]$为$(i,j)$到$(m,n)$范围内的矩形的方案数。
容易想到$dp[m][n] = 2$(一黑一白)。
这里也可以推得边界$dp[i][n] = dp[i + 1][n] + 1,dp[m][j] = dp[m][j + 1] + 1$,意思是开头加上一个黑色棋子的情况加上全部都是白棋子的情况。
这里先给出普遍的公式$dp[i][j] = dp[i + 1][j] + dp[i][j + 1]$。
“$dp[i + 1][j]$”表示第$i$行全放上黑棋子,“$dp[i][j + 1]$”表示第$j$列全放上黑棋子。
为什么是全放上呢?其实第$i$行(第$j$列)放一部分黑和放一部分白的情况已经包含在$dp[i][j+ 1]$($dp[i + 1][j]$)里了。
可以发现按照上面的说法,统计了$2$次全是黑棋的情况,但是又没有统计全是白棋的情况,所以“$+1$”和“$-1$”相互抵消了。
#include <iostream> #include <algorithm> #include <cmath> #define MAXM 32 #define MAXN 32 using namespace std; int m, n; long long f[MAXM][MAXN]; int main() { cin >> m >> n; f[m][n] = 1; for(register int i = m - 1; i >= 1; i--) { f[i][n] = f[i + 1][n] + 1; } for(register int j = n - 1; j >= 1; j--) { f[m][j] = f[m][j + 1] + 1; } for(register int i = m - 1; i >= 1; i--) { for(register int j = n - 1; j >= 1; j--) { f[i][j] = f[i][j + 1] + f[i + 1][j] + 1; } } cout << f[1][1] + 1; return 0; }
参考程序
原文地址:https://www.cnblogs.com/kcn999/p/10805791.html