您的位置:首页 > 其它

uva live 4123 Glenbow Museum 数学递推

2015-08-13 20:55 369 查看
//	uva live 4123 Glenbow Museum 数学递推
//
//	题目大意:
//		
//		对于一个边平行于坐标轴的多边形,我们可以用一个序列来描述,R和O,R表示
//	该顶点的角度为90度,O表示该定点的角度为270.给定序列的长度.问能由这些RO序
//	列组成的星型多边形(内部存在一个点可以看到所有的节点的多边形)的方法数有多少.
//
//	解题思路:
//
//		顶点数一定是序列的长度.n小于4无法组成多边形.n为奇数的时候也不行.设R的个数有
//	x个,O的个数有y个.则90 * x + 270 * y = 180 * (n-2).解得 x = (n + 4) / 2;
//	y = (n - 4) / 2;这样n必为偶数,否则x,y就不是整数了.好的,这样,就可以看到一丝的曙光
//	啦.
//	
//		方法一
//
//		令f(i,j,k,l)表示i个R,j个O,以R(k==0)或O(k==1)开头,以R(l==0)或O(l==1)结尾的合法方案数
//	则递推方程为
//		f(i,j,k,0) = f(i-1,j,k,1) + f(i-1,j,k,0);(可在...R后加R,可在....O后加R);
//		f(i,j,k,1) = f(i-1,j,k,0);
//
//		边界为f(i,0,0,0) = f(0,1,1,1) = 1;
//		最后f(R,O,0,0) + (R,O,1,0) + f(R,O,0,1)就是最后的答案(R,O表示R和O的个数)
//
//		方法二
//
//		令f(i,j,k)表示有i个R,j对R相邻,以R(k==0)或O(k==1)开头的合法方案数,对于j>5的情况
//	对于答案是没有贡献的.因为我们知道有4对相邻的R就一定可以组成星型多边形.
//	递推方程为:
//		f(i,j,k) = f(i-1,j,k) + f(i-1,j-1,k)(首先都是从k开头递推的,这个可以肯定之后,我们
//	可以在现有的...R后有两种选择,一种+OR 对应的是第一项,另一种+R对应的是第二项)
//		边界条件:f(1,0,0) = f(1,0,1) = 1第一个表示R,第二个表示OR.
//
//		方法三:
//
//		组合数学.R的个数有x = (n+4)/2; O的个数有y = (n-4)/2.则问题转化为在x中插入y使得没有两个
//	O相邻.捆绑法,令R在O的左边:
//		1.序列以R开头,这样就是在x中选择y个O与R结成一对.一共C(x,y) = C(x,x-y) = C(x,4)
//		2.序列以O开头,R结尾,这样就是在x-1中选择y-1个O与R组成一队.一共C(x-1,y-1) = C(x-1,4)
//	最后结果为两项之和。
//
//	感悟:
//
//		这道题差不多是在6月份的时候通读训练指南基础篇的时候,看到的这题。当时的自己真的很菜啊。
//	连R和O的个数都要推半天。自己的几何方面实在是太弱了。现在看,虽然能理解。但是不是能立马就能
//	写下状态和转移方程的。自己的递推能力实在太菜了。而且,边界的处理也是有些模糊。可以说是差极了
//	比如在方法一中。我只想到了f(1,0,0,0) = f(0,1,1,1)的状态.却忽视了f(i,0,0,0)=1,其中也是有些转移
//	必须要的.结果自己纠结了半天,还是看到的大牛的题解才恍然大悟.而在看到方法三的时候,顿时不禁眼前一亮
//	这种方法真的太奇妙了.这就是组合数学的奇妙之处.认真体会,发现真的其妙无穷.虽然自己不会写这题,但是
//	看到各位前辈的方案,顿时眼前的思路开阔了一些.一些体会无法用语言形容.继续加油,继续徜徉在这神奇的
//	问题之旅,加油~~~FIGHTING!

			

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>

using namespace std;

typedef long long ll;

ll d[1008][1008][2][2];

void init(){
	memset(d,0,sizeof(d));
	d[1][0][0][0] = 1;
	d[0][1][1][1] = 1;

	for (int i=1;i<=1000;i++)
		d[i][0][0][0] = 1;

	for (int k=0;k<2;k++){
		for (int i=1;i<=1000;i++)
			for(int j=1;j<=1000;j++){
				d[i][j][k][0] = d[i-1][j][k][0] + d[i-1][j][k][1];
				d[i][j][k][1] = d[i][j-1][k][0];
			}
	}
}

int main(){
	init();
	int n;
	freopen("1.txt","r",stdin);
	ios::sync_with_stdio(false);
	int kase = 1;
	while(cin>>n){
		
		if (!n)
			break;
		
		cout << "Case " << kase++ << ": ";
		if (n<4 || (n&1)){
			cout << 0 << endl;
			continue;
		}
		int a = (n+4)/2;
		int b = (n-4)/2;
		ll ans = d[a][b][0][0] + d[a][b][0][1]+d[a][b][1][0];
		cout<< ans << endl;

	}
	return 0;
}

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>

using namespace std;
typedef long long ll;

ll d[1008][8][2];

void init(){
	memset(d,0,sizeof(d));
	d[1][0][0] = 1;
	d[1][0][1] = 1;
	for (int k=0;k<2;k++)
		for (int i=2;i<=1000;i++)
			for (int j=0;j<5;j++){
				d[i][j][k]  = d[i-1][j][k];
				if (j>0)
					d[i][j][k] += d[i-1][j-1][k];
			}
}

int main(){
	init();
	ios::sync_with_stdio(false);
	int n;
	int kase = 1;
	while(cin>>n){
		if (!n)
			break;
		cout << "Case " << kase++ << ": ";
		if (n < 4 || (n&1)){
			cout << 0 << endl;
			continue;
		}
		int a = (n+4)>>1;

		ll res = d[a][4][0] + d[a][4][1] + d[a][3][1];
		cout << res << endl;
	}
}

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;
typedef long long ll;
int main(){
	ll n;
	ios::sync_with_stdio(false);
	int kase = 1;
	while(cin>>n){
		if (!n)
			break;
		cout << "Case " << kase++ << ": ";
		if (n<4 || (n & 1)){
			cout << 0 << endl;
			continue;
		}
		ll r = (n+4)/2;

		ll ans1 = r * (r-1) * (r-2) * (r-3) / 24;
		r--;
		ll ans2 = r * (r-1) * (r-2) * (r-3) / 24;
		cout << ans1 + ans2 << endl;

	}
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: