bzoj1087: [SCOI2005]互不侵犯King 状压dp

在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子。

第一眼看成k皇后问题了,仔细一看原来是状压dp,dp【i】【j】【k】i是滚动数组压缩形式,j是上一层的状态,k是已经用过的国王数,那么转移很明显,从上一层转移到下一层,枚举两层的所有状态看会不会冲突,不冲突就能转移,d[now][j][num+k]+=dp[pre][i][k],now是这一层用过的国王数。,最后记录满足条件的k即可,复杂度O(n^2*2^2n),大约是1e8

/**************************************************************
    Problem: 1087
    User: walfy
    Language: C++
    Result: Accepted
    Time:572 ms
    Memory:4604 kb
****************************************************************/
 
//#pragma comment(linker, "/stack:200000000")
//#pragma GCC optimize("Ofast,no-stack-protector")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
//#pragma GCC optimize("unroll-loops")
#include<bits/stdc++.h>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define pi acos(-1.0)
#define ll long long
#define vi vector<int>
#define mod 1000000007
#define C 0.5772156649
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
#define pil pair<int,ll>
#define pli pair<ll,int>
#define pii pair<int,int>
#define cd complex<double>
#define ull unsigned long long
#define base 1000000000000000000
#define fio ios::sync_with_stdio(false);cin.tie(0)
 
using namespace std;
 
const double g=10.0,eps=1e-12;
const int N=1000+10,maxn=100000+10,inf=0x3f3f3f3f,INF=0x3f3f3f3f3f3f3f3f;
 
ll dp[2][N][200+10];
int main()
{
    int n,k;
    scanf("%d%d",&n,&k);
    int now=1,pre=0;
    for(int i=0;i<(1<<n);i++)
    {
        int num=0,ok=1;
        for(int j=0;j<n;j++)
        {
            if((i>>j)&1)num++;
            if(j&&((i>>(j-1))&1)&&((i>>j)&1)){ok=0;break;}
        }
        if(ok)
        {
            dp[pre][i][num]++;
//            printf("%d %d %d\n",i,num,dp[pre][i][num]);
        }
    }
    for(int _=2;_<=n;_++)
    {
        memset(dp[now],0,sizeof dp[now]);
        for(int i=0;i<(1<<n);i++)//last
        {
            for(int j=0;j<=k;j++)//last k
            {
                for(int u=0;u<(1<<n);u++)
                {
                    if(dp[pre][i][j]==0)continue;
                    int num=0,ok=1;
                    for(int v=0;v<n;v++)
                    {
                        int st=(u>>v)&1,last=(i>>v)&1;
                        if((u>>v)&1)num++;
                        if(st&&last)
                        {
                            ok=0;
                            break;
                        }
                        if(v>0)
                        {
                            last=(i>>(v-1))&1;
                            if(st&&last){ok=0;break;}
                            last=(u>>(v-1))&1;
                            if(st&&last){ok=0;break;}
                        }
                        if(v<n-1)
                        {
                            last=(i>>(v+1))&1;
                            if(st&&last){ok=0;break;}
                            last=(u>>(v+1))&1;
                            if(st&&last){ok=0;break;}
                        }
                    }
                    if(ok)
                    {
//                        printf("last = %d ++ last k = %d ++ now = %d dp[pre][i][j] = %d ++ num+j = %d\n",i,j,u,dp[pre][i][j],num+j);
                        dp[now][u][num+j]+=dp[pre][i][j];
//                        printf("%d %d %d %d\n",now,u,num+j,dp[now][u][num+j]);
                    }
                }
            }
        }
        swap(now,pre);
    }
    ll ans=0;
    for(int i=0;i<(1<<n);i++)
        ans+=dp[pre][i][k];
    printf("%lld\n",ans);
    return 0;
}
View Code

 

posted @ 2018-04-14 14:38  walfy  阅读(171)  评论(0编辑  收藏  举报