bzoj1087[SCOI2005]互不侵犯King

20 篇文章 0 订阅

题意:给定n,k,在n*n个棋盘里放k个棋子,让他们不能互相攻击,有多少种方案,一个棋子可以攻击他的八个方向。

题解:很久没打状压DP了,一脸懵逼,本来状压就不是很好,现在弱的一匹。。表示这题一脸不可做,不得已去膜了一波题解。
有一个很好的题解http://blog.csdn.net/qpswwww/article/details/34516641
这题主要是如果直接dp状态数会很大,那么我们就可以把每一行的状态压缩一下,然后提前预处理每一行的方案数,然后再预处理前两行的合法性(不被攻击),接着就能直接往下dp了,细节有点多,看不懂的话看代码,代码看不懂上面那个网址的代码的注释写的很好,比较推荐。

#include<stdio.h>
#define N 100
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef long long ll;
ll f[N][N][600],ans;
int stay[N],map[N][N],cnt[N],n,k,m=0;
inline void predfs(int x,int pos,int now)
{
    int i;
    stay[++m]=now;
    cnt[m]=x;
    if (x>=(n+1/2)||x>=k)return;
    fo(i,pos+2,n)
    predfs(x+1,i,now+(1<<(i-1)));
}
inline void premap()
{
    int i,j;
    fo(i,1,m)
    fo(j,1,m)
    {
        map[i][j]=map[j][i]
        =((stay[i]&stay[j])||((stay[i]>>1)&stay[j])||((stay[i]<<1)&stay[j]))?0:1;
    }
    fo(i,1,m)
    f[1][cnt[i]][i]=1;
}
int main()
{
    int i,j,now,h;
    scanf("%d%d",&n,&k);
    predfs(0,-1,0);
    premap();
    fo(i,2,n)
    {
        fo(j,0,k)
        {
            fo(now,1,m)
            {
                if (cnt[now]>j)continue;
                fo(h,1,m)
                if (map[h][now]&&cnt[h]+cnt[now]<=j)
                f[i][j][now]+=f[i-1][j-cnt[now]][h];
            }
        }
    }
    fo(i,1,m)
    ans+=f[n][k][i];
    printf("%lld\n",ans);
    return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值