Nyoj 492 King 状态压缩

题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=492

题目大意:n*n的棋盘上放k个国王(可攻击相邻的8个格子),求使它们无法互相攻击的方案数。输入n和k(0<n<=10,0<k<=n^2)。

解题思路:数据很小,可以用状态压缩。

首先 对于每行所有状态,我们可以 先处理出  有效状态(即在一行的所有国王不会相互攻击的状态),用  sta[]表示,其中  ct 表示有效状态总数。

其次 对于每种合法状态,我们要计算出在该种状态下,放的国王数,用cnt[]表示。

我们可以定义  dp[i][j][k]为  在第i行的第j个状态 已经放了k个 国王的方案数,则状态转移方程如下:

dp[i][j][k1+cnt[j]]=dp[i][j][k]+dp[i-1][j1][k1];

表示  在第i行的第j个状态 已经放了k个 国王的方案数  是由第i-1行 第j1个状态  已经放了k1个国王的状态转移过来,如果可以转移,则转移到的状态需加上j行cnt[j];

其中  也可以预先处理出相邻两行的合法状态,这样会更快,也可以用滚动数组优化 空间,但下面的代码还是比较朴素的代码。

代码如下:

 #include<cstdio>
 #include<cstring>
 #include<algorithm>
 using namespace std;
 int n,k;
 long long dp[11][150][105];
 int sta[150],cnt[150];
 void init()
 {
     memset(dp,0,sizeof(dp));
     memset(sta,0,sizeof(sta));
     memset(cnt,0,sizeof(cnt));
 }
 void solve()
 {
    int num=(1<<n),ct=0;

    for(int i=0; i<num; i++)//合法状态数
        if(  !(i&(i<<1)) )
            sta[ct++]=i;
    for(int i=0; i<ct; i++)
    {
        int cot=0;
        for(int j=0; j<n; j++) //每个合法状态的国王个数
            if( sta[i]&(1<<j) )
                cot++;

        if(cot<=k)           //预处理第0行
            dp[0][i][cot]=1;

        cnt[i]=cot;
    }

    for(int i=1; i<n; i++)
        for(int j=0; j<ct; j++)
            for(int p=0; p<ct; p++)
            {
                if( (sta[j]&sta[p]) || (sta[j]&(sta[p]>>1)) ||  (sta[j]&(sta[p]<<1)) ) continue;
                for(int k1=0; k1<=k; k1++)
                    if( k1+cnt[j]<=k )
                        dp[i][j][k1+cnt[j]]+=dp[i-1][p][k1];
            }

    long long ans=0;
    for(int i=0;i<ct;i++)
        ans+=dp[n-1][i][k];
    printf("%lld\n",ans);
 }
 int main()
 {
     while(~scanf("%d%d",&n,&k))
     {
         init();
         solve();
     }
     return 0;
 }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值