这道题目的第一感觉肯定是很像八皇后!!!可是它并不是八后所以我们需要使用一种逆向思维去思考!
题目大家应该都知道了,我就不讲了,这里主要讲思路:
重新描述一下问题,其实就是在一个边长为 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;
}