状态压缩基础题2道

来源:互联网 发布:手机双桌面软件 编辑:程序博客网 时间:2024/06/08 10:14

最近队友们都在专注状态压缩,于是果断凑凑热闹。。。。昨天看了他们正在看的一份资料,写的非常不错,话说国家集训队论文对我这个小菜鸟而言高深莫测,各种看不懂,这份资料可以说写的相当不错,由浅入深,最重要的是细节部分写的很到位(PS:其实看集训队论文还是经典的,但需要读者有较好的基本功的)

对状态压缩已有了最基本的了解,尤其是预处理意识对初学者来讲很重要的,它可以减少代码复杂度和时间复杂度。此外,位运算代码书写要格外注意哟,好,开始上题。


POJ 1185 炮兵阵地

这是经典的老NOI试题,状态压缩入门必刷题。首先是预处理每一行中哪些状态时可行的,用dfs实现。状态转移方程F[i][S1][S2] = max{F[i-1][s2][s3]},s1,s2,s3为第i行,i-1行,i-2行状态。并且三个状态之间不冲突。由于需要空间过多,需要滚动数组,附代码:

#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <cmath>#include <vector>#define N 104#define M 1027#define pb push_back#define ss(a) scanf("%d",&a)#define cl(a) memset(a,0,sizeof(a))using namespace std;int a[N],m,n,res;vector<int> s[N];int f[2][M][M],bit[M];void clearing(){    cl(f);cl(a);    for (int i=1;i<=n;i++) s[i].clear();}void init(int i,int x,int d,int value){    int j;    if (i<0)    {        s[0].pb(value);        bit[value]=d;        for (j=1;j<=n;j++)            if ((value&a[j])==value) s[j].pb(value);    }    else    {        init(i-1,x,d,value);        if (x<0||x-i>2)        {            int t=1<<i;            init(i-1,i,d+1,value+t);        }    }}void inition(){    int i,j;    for (i=0;i<(1<<m);i++)    {        for (j=0;j<(1<<m);j++)            if ((i&a[1])==i) f[1][i][j]=bit[i];        res=max(res,f[1][i][0]);    }        }int main(){    int i,j,k,l,x,y,z,e;    while (ss(n)!=EOF)    {        ss(m);        clearing();        for (i=1;i<=n;i++)            for (j=1;j<=m;j++)            {                char ch;                cin>>ch;                if (ch=='P') a[i]+=(1<<(m-j));            }        init(m-1,-1,0,0);        res=-1;        inition();        for (i=2;i<=n;i++)            for (j=0;j<s[i].size();j++)            {                x=s[i][j];                for (k=0;k<s[i-1].size();k++)                {                    y=s[i-1][k];                    e=i%2;                    f[e][x][y]=0;                    if (!(x&y))                    {                        for (l=0;l<s[i-2].size();l++)                        {                            z=s[i-2][l];                            if (i==2||!((x&z)||(y&z)))                            {                                f[e][x][y]=max(f[e][x][y],f[1-e][y][z]+bit[x]);                                }                        }                    }                    res=max(res,f[e][x][y]);                }            }        printf("%d\n",res);          }    return 0;}

POJ 2411

还是一道很经典的题,方块问题。F[i][S]=sigma(f[i-1][s1]),其中s和s1无重复单元格,并填满上一行。注意S1可以使全0状态。初始值F[0][2^W-1]=1。要用到i64,附代码:

#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <cmath>#define ll __int64#define N (1<<11)+10#define u (1<<w)-1#define ss(a,b) scanf("%d%d",&a,&b)#define cl(a) memset(a,0,sizeof(a))using namespace std;int a[N][N],w;ll  f[13][N];int pd(int i,int j,int w){    int p,q,x=1,y=0,k;    if ((i|j)!=u) return 0;    for (k=0;k<w;k++)    {        p=i&x;        q=j&x;        if (p&q) y=(y+1)%2;        else if (y!=0) return 0;        x*=2;    }    if (y) return 0;    else return 1;}int main(){    int i,j,k,m,n,h;    while (ss(h,w)!=EOF)    {        if (h==0&&w==0) break;        if ((h*w)%2>0)         {            cout<<0<<endl;            continue;        }        cl(a);        for (i=0;i<=u;i++)            for (j=0;j<=u;j++)                if (pd(i,j,w)) a[i][j]=1;        cl(f);        f[0][u]=1;        for (i=1;i<=h;i++)            for (j=0;j<=u;j++)                for (k=0;k<=u;k++)                    if (f[i-1][j]>0&&a[j][k])                    {                        f[i][k]+=f[i-1][j];                    }        printf("%I64d\n",f[h][u]);    }    return 0;}


原创粉丝点击