[简单dp]toj1179

题意给2n个点,问把他们两两连接有多少种方案,线段不允许交叉。

哎,感觉我好水。。。打了两天CF,但是笔记本掉帧太厉害,没兴致玩了。明天来鸡房呆着敲代码吧。。。

假设有p个点,当然题目给了n表达的是2n,所以p一定是偶数。顺序标号后发现,只需要考虑第一个点和谁连接就好了,因为有个线段不能相交的条件,所以一旦确定了第一个点连出的线段,这p个点就被这线段分成了两部分。很容易知道每部分的点数必须为偶数,否则一定产生交点。那么就很简单了,只需要考虑第一个点和第2,4,6,8,...,p连接的情况就可以了,定义dp[i]表示i个点的方案数,那么:

dp[i] = dp[i-2] + dp[2]*dp[i-4] + dp[4]*dp[i-6] + ... + dp[n-2]

为了表达方便,初始化dp[0]为1,那么上述转移就是:dp[i] = dp[j]*dp[i-2-j] (j=0,2,4,...,i-2)

C++代码:

#include<cstdio>

typedef long long ll;
const int MAX = 202;
ll dp[MAX] = {1, 0, 1};

int main() {
	for (int i = 4; i < MAX; i += 2) {
		for (int j = 2; j <= i; j += 2) {
			dp[i] += dp[i-j] * dp[j-2];
		}
	}
	
	int n;
	while (~scanf(" %d", &n) && (~n)) {
		printf("%lld\n", dp[n<<1]);
	}
	return 0;
}
当然,这是很糟糕的代码:点数达到一定量后溢出long long了,所以还是大整数(Java版):

import java.util.*;
import java.math.*;

public class Main {
	public static void main(String args[]) {
		BigInteger []dp = new BigInteger[202];
		dp[0] = BigInteger.valueOf(1);
		dp[2] = BigInteger.valueOf(1);
		for (int i = 4; i < 202; i += 2) {
			dp[i] = BigInteger.ZERO;
			for (int j = 2; j <= i; j += 2) {
				dp[i] = dp[i].add(dp[i-j].multiply(dp[j-2]));
				//System.out.println("dp[" + i + "] = " + dp[i]);
			}
		}
		
		Scanner cin = new Scanner(System.in);
		int n;
		while (cin.hasNextInt()) {
			n = cin.nextInt();
			if (n == -1) break;
			System.out.println(dp[n<<1]);
		}
	}
}
好吧,我狠无聊,好想打字...只是缓解一下两天没有敲代码的手瘾...吃翔去了╮(╯▽╰)╭

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值