bzoj1087: [SCOI2005]互不侵犯King

来源:互联网 发布:sketchup2016 mac 编辑:程序博客网 时间:2024/04/28 10:38

这道题我作为初学者来看有些懵。。
上网搜了一下发现大神都说是状态压缩。。
所以就开始学了一下状态压缩
状态压缩就是把每一行的状态转化为2进制,0表示不填,1表示填,只问合法状态,不用把每一个状态都问一遍。。
对时间和空间都很节省。。
这道题的dp方程也不难想(只要你会状压)。。
学会了状压之后很快就做出来了。。这道题还是比较入门。。

#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>#include<sstream>using namespace std;long long f[11][(1<<11)+10][90];     //f[i][j][k]表示第i行填j状态,填完之后前i行有k个king long long a[16][16],v[(1<<9)+10],vn;long long t[610];char s[110000];int n;int main() {    //freopen("king.in","r",stdin);freopen("king.out","w",stdout);    for(int i=1;i<=600;i++) {  //t数组表示每一个状态有多少个1         int xx=i,m=0;        while(xx!=0) {            if(xx%2==1)                m++;            xx/=2;        }        t[i]=m;    }    int k;    scanf("%d%d",&n,&k);    memset(f,0,sizeof(f));    int mmax=(1<<n)-1;    for(int x=0;x<=mmax;x++) {   //存有用的状态         if(((x<<1)&x)==0) {            f[1][x][t[x]]=1;            v[++vn]=x;        }    }    for(int i=2;i<=n+1;i++)        for(int p=1;p<=vn;p++) {            for(int q=1;q<=vn;q++)                 if((v[p]&v[q])==0&&((v[p]>>1)&v[q])==0&&((v[p]<<1)&v[q])==0)   //状态是否合法                     for(int ii=k;ii>=t[v[p]];ii--)                        f[i][v[p]][ii]=f[i][v[p]][ii]+f[i-1][v[q]][ii-t[v[p]]]; //dp方程         }    printf("%lld\n",f[n+1][0][k]);          //n+1行不填表示了前n行所有的状态     return 0;}
0 0