计蒜客:墙壁涂色

墙壁涂色

Description

蒜头君觉得白色的墙面好单调,他决定给房间的墙面涂上颜色。他买了 3 种颜料分别是红、黄、蓝,然后把房间的墙壁竖直地划分成 nn 个部分,蒜头希望每个相邻的部分颜色不能相同。他想知道一共有多少种给房间上色的方案。例如,当 n=5 时,下面就是一种合法方案。

蓝|红|黄|红|黄

由于墙壁是一个环形,所以下面这个方案就是不合法的。

蓝|红|黄|红|蓝

Input

一个整数 n,表示房间被划分成多少部分。(1≤n≤50)

Output

一个整数,表示给墙壁涂色的合法方案数。


一问到方法数,我第一时间联想到的是深搜(之前肝了三天的深搜),不过在这里深搜貌似会超时...(心情简单)。于是我想到用动态规划来做。这里为了看着方便(其实是写着舒服),我将红色定义为1,黄色定义为2, 蓝色定义为3。由于这里只有三种颜色,每块相邻的墙颜色又不能相同,所以我们可以得出第i块墙的一种情况能够得出第(i + 1)块墙的两种情况。我假设第一块墙涂上红色,那么第二块墙就有1 * 2 = 2种情况,第三块墙就有2 * 2 = 4种情况。对于第i块墙壁,则有2^(i - 1)种情况。

由于墙壁又是环形的,所以我们不能够让最后一块的颜色与第一块的相同。因此我们需要将第n块墙的所有情况中与第一块墙不相等的情况找出来,也就是说我们只需要数一下有几种情况是与第一块相同的,然后用总的情况数减掉它就可以了。假设我们仍然第一块涂红色,现在涂到了第i块墙。然后我们将第(i - 1)块墙的涂法看做两种:涂红色和不涂红色。如果是涂的红色,那么第i块墙就不会涂红色,因此这种情况不考虑。如果涂的其它颜色,那么涂下的这种颜色就会对第i块墙产生两种情况:红色和第三种颜色。所以说第(i -1)块墙每种不涂红色的情况都会使第i块墙产生一种涂红色的情况,而第(i - 1)块墙不涂红色的情况等于第(i - 1)块墙的所有情况减去涂红色的情况。于是第i块墙涂红色的情况数就可以用一个方程来求:red[i] = all[i - 1] - red[i - 1]。最后算到n就是第一块墙涂红色时最后一块墙也是红色的所有情况了,再用第n块墙的总情况数来减,就得到了第一块墙涂红色时的合法情况数了。而对于总情况数,我们之前已经做过推理,可以得出all[i] = all[i - 1] * 2。算出第一块墙涂红色的合法情况数,由于总共有三种颜色,所以再乘3就可以得出所有的合法情况数了。于是我们就可以码代码了:

#include
using namespace std;
const int maxn = 50 + 5;

long long num[2][maxn];//这里用两层数组来存储情况数,第一层是第i块墙涂红色的情况,第二层是第i块的总情况数

int main(){
	int n;
	cin >> n;
	
	num[0][1] = 1, num[1][1] = 1, num[0][2] = 0, num[1][2] = 2;
	int cnt = 0;
	for(int i = 3; i <= n; i++){
		num[0][i] = num[1][i - 1] - num[0][i - 1];
		num[1][i] = num[1][i - 1] * 2;
	}
	
	cout << (num[1][n] - num[0][n]) * 3;
	return 0;
}

 

你可能感兴趣的:(题解,计蒜客,dp,YCOJ)