码迷,mamicode.com
首页 > 其他好文 > 详细

UVA 1073 - Glenbow Museum(数论+计数问题+递推)

时间:2014-05-11 14:41:25      阅读:293      评论:0      收藏:0      [点我收藏+]

标签:style   blog   class   code   tar   c   

题目链接:1073 - Glenbow Museum

白书上的例题,需要一定的推理。
首先要把问题转化,推理出n个点,R的个数为(n + 4) / 2, O的个数为(n - 4) / 2个,因为首先四个角必须为R,然后在中间添加O点,每有一个O点就要多一个R点,所以最后R点比O点多4。
然后问题就转化为给定n个R点和m个O点,求出有多少个序列,要求O点不连续,并且R的连续个数不能超过4,的序列个数。
可以设状态dp[i][j][2][2],表示用到第i个R点第j个O点,开头点,结尾点,的情况种数来进行状态转移。
然后白书上有一种更高效的方法,因为连续的R的个数不可能超过O的数个4个以上,所以当i - j > 5的值是对答案没影响的。
所以设状态为dp[i][j][2],表示i个R,已经有j对R(最多有4对R),开头点,末尾为R的状态,状态转移方程为
dp[i][j][k] = dp[i - 1][j][k] (末尾添加OR) + sum{dp[i - 1][j - 1][k]} (末尾添加R),  k = 0 表示开头为R,k = 1表示开头为O。
ans[n] = dp[n][3][0] + dp[n][4][1] + dp[n][4][0](末尾还需补个O)
代码:
#include <stdio.h>
#include <string.h>

const int N = 505;
int n;
long long ans[N * 2], dp[N][5][2];

void DP() {
	for (int k = 0; k < 2; k++) {
		dp[1][0][k] = 1;
		for (int i = 2; i < N; i++) {
			for (int j = 0; j < 5; j++) {
				dp[i][j][k] = dp[i - 1][j][k];
				if (j > 0)
					dp[i][j][k] += dp[i - 1][j - 1][k];
			}
		}
	}
}

void init() {
	DP();
	for (int i = 1; i <= 1000; i++) {
		int n = (i + 4) / 2;
		if (i % 2 || i < 4) ans[i] = 0;
		else ans[i] = dp[n][3][0] + dp[n][4][1] + dp[n][4][0];
	}
}

int main() {
	init();
	int cas = 0;
	while (~scanf("%d", &n) && n) {
		printf("Case %d: %lld\n", ++cas, ans[n]);
	}
	return 0;
}


UVA 1073 - Glenbow Museum(数论+计数问题+递推),布布扣,bubuko.com

UVA 1073 - Glenbow Museum(数论+计数问题+递推)

标签:style   blog   class   code   tar   c   

原文地址:http://blog.csdn.net/accelerator_/article/details/25473649

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!