UVA 861 Little Bishops

https://vjudge.net/problem/UVA-861

 

题意:

在n*n棋盘上方k个互不攻击的象,求方案数

若两个象在同意对角线上,则会互相攻击

 

将棋盘黑白染色,则黑格不会攻击白格,白格不会攻击黑格

所以黑白格分开考虑

最终答案= Σ 黑格放i个*白格放k-i个

将所有黑格抽离出来,旋转45°

这样对角线方向就变成了水平方向和竖直方向

问题转化成了 每一行每一列至多放1个

在按每行格子数量从小到大排序

这样每行依次为 2个、2个、4个、4个、6个、6个、8个、8个……

或者每行一次为 1个、1个、3个、3个、5个、5个、7个、7个……

dp[i][j] 表示前i行放了j个的方案数

如果第i行不放,就是dp[i-1][j]

如果第i行放,有j-1列在前i-1行放过了,所以第i行有 该行格数-(j-1)个 位置可以放,就是 dp[i-1][j-1]*(sum-j+1)

用s[i]表示第i行有多少格子

dp[i][j]=dp[i-1][j]+dp[i-1][j-1]*(s[i]-j+1)

这样就求出只有黑格或者只有白格的情况,再合并即可

 

vjudge一直在pending,先把代码粘上吧。。。。。。

 

#include<cstdio>
#include<cstring>

using namespace std;

#define N 9
typedef long long LL;

int b[N],w[N]; 
LL f[N][N],g[N][N]; 

void solve(int n,int k,int s[N],LL dp[N][N])
{
    memset(dp,0,sizeof(dp));
    for(int i=0;i<=n;++i) dp[i][0]=1;
    for(int i=1;i<=n;++i)
        for(int j=1;j<=k && j<=i;++j)
            dp[i][j]=dp[i-1][j]+dp[i-1][j-1]*(s[i]-j+1); 
}

int main()
{
    int n,k;
    LL ans;
    b[1]=2;
    for(int i=2;i<=8;++i)
        if(i&1) b[i]=b[i-1]+2;
        else b[i]=b[i-1];
    w[1]=1;
    for(int i=2;i<=8;++i)
        if(i&1) w[i]=w[i-1]+2;
        else w[i]=w[i-1];            
    while(1)
    {
        scanf("%d%d",&n,&k);
        if(!n && !k) return 0; 
        solve(n-1,k,b,f);
        solve(n,k,w,g);
        ans=0;
        for(int i=0;i<=k;++i) 
            if(i<=n && k-i<=n) ans+=f[n-1][i]*g[n][k-i];
        printf("%lld\n",ans);
    }
}
         

 

posted @ 2020-01-30 22:18  TRTTG  阅读(284)  评论(0编辑  收藏  举报