[caioj]1489: 基于连通性状态压缩的 动态规划问题:Formula 1

来源:互联网 发布:linux man pages 编辑:程序博客网 时间:2024/05/22 06:25

【题目描述】
给你一个 n *m 的棋盘,有的格子是障碍,问共有多少条能经过每个非障碍格子恰好一次的回路(n,m ≤ 12),回路只能有一条。

插头DP入门题,入门建议结合cdq的论文,各种blog,代码学习。

注意事项:

1、要用hash,虽然算出来的状态没有这么多,但是在行与行之间转移状态的时候,会新增很多状态,所以用hash。
2、虽然只有0、1、2三个数,但是状态一般用四进制数存储,因为方便更改、查询某一位。
3、一定要把边界设为障碍点!

代码:

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;#define LL long longconst int mod=100037;int n,m,map[15][15],xx=-1,yy,now=0,list[2][mod],num[2];//                              状态列表         状态总数 LL state[2][mod],ans=0;//每种状态的数目int HASH[mod];LL get(int s,int p)//获取状态s从右向左数的第p位 {return (s>>((p-1)*2))&3;}void change(int &s,int p,int v)//把状态s的第p位改成v {    s^=get(s,p)<<((p-1)*2);    s^=(v)<<((p-1)*2);}void add(int now,int st,LL sum){    int ss=st%mod;    while(list[now][HASH[ss]]!=st&&HASH[ss]!=-1)    {        ss++;ss%=mod;        if(ss==0)ss=1;    }    if(HASH[ss]==-1)    {        HASH[ss]=++num[now];        list[now][num[now]]=st;        state[now][num[now]]=sum;    }    else state[now][HASH[ss]]+=sum;}void work(){    state[0][1]=1;num[0]=1;list[0][1]=0;    for(int i=1;i<=n;i++)    {        for(int j=1;j<=m;j++)        {            now^=1;            num[now]=0;            memset(HASH,-1,sizeof(HASH));            for(int k=1;k<=num[now^1];k++)            {                int st=list[now^1][k];//获取上次的状态                 LL sum=state[now^1][k];//获取此状态的数目                 int p=get(st,j);//获取上次的两个插头                 int q=get(st,j+1);                if(!map[i][j])//障碍点                {                    if(!p&&!q)add(now,st,sum);                    continue;                }                if(!p&&!q)//没有连到当前的格子                 {                    if(map[i][j+1]&&map[i+1][j])                    {                        change(st,j,1);                        change(st,j+1,2);                        add(now,st,sum);                    }                }                else if(!p&&q)                {                    if(map[i][j+1])add(now,st,sum);                    if(map[i+1][j])                    {                        change(st,j,q);                        change(st,j+1,0);                        add(now,st,sum);                    }                }                else if(p>0&&!q)                {                    if(map[i+1][j])add(now,st,sum);                    if(map[i][j+1])                    {                        change(st,j,0);                        change(st,j+1,p);                        add(now,st,sum);                    }                }                else if(p==1&&q==2)                {                    if(i==xx&&j==yy)                    ans+=sum;                }                else if(p==2&&q==1)                {                    change(st,j,0);                    change(st,j+1,0);                    add(now,st,sum);                }                else if(p==1&&q==1)                {                    int top=1;                    for(int pos=j+2;pos<=m+1;pos++)                    {                        int temp=get(st,pos);                        if(temp==1)top++;                        if(temp==2)top--;                        if(top==0)                        {                            change(st,j,0);                            change(st,j+1,0);                            change(st,pos,1);                            add(now,st,sum);                            break;                        }                    }                }                else if(p==2&&q==2)                {                    int top=1;                    for(int pos=j-1;pos;pos--)                    {                        int temp=get(st,pos);                        if(temp==2)top++;                        if(temp==1)top--;                        if(top==0)                        {                            change(st,j,0);                            change(st,j+1,0);                            change(st,pos,2);                            add(now,st,sum);                            break;                        }                    }                }            }        }        for(int j=1;j<=num[now];j++)list[now][j]<<=2;    }}int main(){    memset(map,0,sizeof(map));    scanf("%d%d",&n,&m);    for(int i=1;i<=n;i++)    {        char str[15];        scanf("%s",str);        for(int j=1;j<=m;j++)        {            if(str[j-1]=='.')            map[i][j]=1,xx=i,yy=j;        }    }    if(xx==-1){puts("0");return 0;}    work();    printf("%lld",ans);}
阅读全文
2 0
原创粉丝点击