[简单dp]toj1179

来源:互联网 发布:微博域名可以修改吗 编辑:程序博客网 时间:2024/06/05 01:59

题意给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]);}}}
好吧,我狠无聊,好想打字...只是缓解一下两天没有敲代码的手瘾...吃翔去了╮(╯▽╰)╭

0 0
原创粉丝点击