诸侯安置 搜索02 empire

来源:互联网 发布:股票 知乎 编辑:程序博客网 时间:2024/04/27 15:50

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