UVA---1073:Glenbow Museum(dp or 组合数)

题意:

给定顶点数L,求L个顶点围成的多边形的角度字符串有多少个不同的

分析:

XJB分析,开始4个顶点可以围成唯一的一个,替换掉其中的一个R,只能用ROR去替换,才能使其封闭,那么只有从4开始的偶数才有解,且O的数量为 :(L-4)/ 2,R的数量为:L - (L-4) / 2

简化成:给定x个O和y个R,求组成的字符串有多少个,且满足不能有两个O相连(首尾也要算)

方法1:排列组合

考虑在y个R的排列的空隙中插入x个O,要考虑首尾相邻的情况

(1)尾插入O,则首不能插入O:

那么剩余x-1个O,y-1个空隙可用的方案为:C_{y-1}^{x-1}

(2)尾不插入O:

那么剩余x个O,y个空隙可用的方案为:C_{y}^{x}

答案为:C_{y}^{x}+C_{y-1}^{x-1}

方法2:动态规划

定义dp[i][j][k][R/O][O/R],表示前i个位置中用了j个O,k个R,首为R/O,尾为O/R的方案数,

初始化:dp[2][1][1][0][1] = 1;dp[2][1][1][1][0] = 1; dp[2][0][2][1][1] = 1;从3开始递推,开滚动数组优化即可

代码:

#include <bits/stdc++.h>

using namespace std;
typedef long long LL;
LL dp[2][1005][1005][2][2];
int main()
{
    int T = 1,n;
    while(cin >> n && n)
    {
        printf("Case %d: ",T++);
        if(n&1 || n < 4)
        {
            cout << 0 << '\n';
            continue;
        }
        int x = (n-4) / 2;     //O : 0
        int y = n - x;         //R : 1
        dp[0][1][1][0][1] = 1;
        dp[0][1][1][1][0] = 1;
        dp[0][0][2][1][1] = 1;
        for(int i = 3; i <= n; ++i)
        {
            int q = i&1,p = (i-1)&1;
            for(int j = 0; j <= x; ++j)
            {
                int k = i - j;
                if(k){
                    dp[q][j][k][0][1] = dp[p][j][k-1][0][0]+dp[p][j][k-1][0][1];
                    dp[q][j][k][1][1] = dp[p][j][k-1][1][0]+dp[p][j][k-1][1][1];
                }
                if(j){
                    dp[q][j][k][1][0] = dp[p][j-1][k][1][1];
                    dp[q][j][k][0][0] = dp[p][j-1][k][0][1];
                }
            }
        }
        cout << dp[n&1][x][y][0][1] + dp[n&1][x][y][1][0] + dp[n&1][x][y][1][1]<< '\n';
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41157137/article/details/89309235