诸侯安置 搜索02 empire

这道题目的第一感觉肯定是很像八皇后!!!可是它并不是八后所以我们需要使用一种逆向思维去思考!
题目大家应该都知道了,我就不讲了,这里主要讲思路:
重新描述一下问题,其实就是在一个边长为 2n-1 的正菱形(如上左图为 n=3的情形)上摆放 k 个棋子,使得任意两个棋子都不在同一行、同一列。试问:这样的摆法共有多少种?

看到这道题目,我们就会立即想起一道经典的老题目:n 皇后问题。这道题目与 n 皇后问题非常相似。但有两个不同点:一是 n 皇后问题可以斜着攻击对方棋子,而本题不能;二是 n 皇后问题是在 n,n 的正方形棋盘上面放置 k 个皇后,而本题却是在一个正菱形上摆放。我们试着先将 n 皇后变为不可斜攻的,再作思考,如果不能够斜着攻击,n 皇后的公式是:(C(k,n))^2*k!。但是本题不是一个正方形,所以这个公式对本题好像没有任何帮助。看来只能够从另外一个角度思考问题了。

首先想到在 2n-1 列中任意取出 k 列进行具体分析,这样一来问题就转化成:有一个长为 k 的数列(无重复元素),每一个数在一个不定的区间[a,b]当中,第 i 个数一定在区间[ai,bi]之间,求这样的数列有多少种? 如果就是这个问题,那么比较难解决,但若把这个数列放在本题中,就比较简单。

因为题目中任意两个区间都是一种包含关系。可以先把区间按照长度排一下序,就可以看出来,再用乘法原理进行求解即可。但是,n 最多可到 100,k 最多可到 50,穷举要进行 C(50,100)种方案! 显然无法在 1s 内出解!那么怎么办呢?

再继续分析一下问题发现,里面有重叠子问题。如果一个列作为最后一列,且这一列以及前面所有列共放置 p 个诸侯,设有 q 种情况,那么这一列后面的所有列共放置 p+1 个棋子的方案数都要用到 q,从而引用乘法原理。而且在穷举过程中,这一个工作做了许多遍,所以干脆用递推。递推前,先把图形转化为类似右图的形式(即列排序)。
设 f[i,j]表示以第 i 列为最后一列,放置 j 个棋子的总方案数,得出公式:
i-j+1
Σf[i-k][j-1]*(i-j-1+i*2);
k=1
不过还要注意,当 k≥2n-1 时,问题无解。
下面放代码:

#include<stdio.h>   
#include<stdlib.h>
int dp[5000][5000];
int main(){
    int i,j,k,n,m;
    freopen("empire.in","r",stdin);
    freopen("empire.out","w",stdout);  
    scanf("%d%d",&n,&m);
    n=2*n-1;
    if(m==0){
        printf("1\n");return 0;
    }
    if(m>=n){
        printf("0\n");return 0;
    }
    for(i=1;i<=n;i++)
        if(i%2==1)dp[i][1]=i;
        else dp[i][1]=i-1;
    for(i=1;i<=n;i++)
        for(j=2;j<=i;j++)
            for(k=1;k<=i-j+1;k++){
                dp[i][j]+=dp[i-k][j-1]*(i-j+i%2);
                dp[i][j]%=504;
            }  
    for(i=m;i<n;i++)  {  
        dp[n][m]+=dp[i][m];  
        dp[n][m]%=504;  
    }  
    printf("%d\n",dp[n][m]);  
    return 0;  
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值