赞
踩
插头dp通常用来解决棋盘上的连通性、回路问题,采用按格递推的方式求解,虽然理论状态较多,但是实际的合法状态较少
令f [ i , j , s ] 表示递推到 i , j 这个格子,状态是 s
插头dp枚举格子时需要 记录 x , y哪条边有边伸出,记录属于哪个连通块,(这样说有点抽象,等会画图就清楚了),记录连通块有两种方法,最小表示法和括号表示法
最小表示法

括号表示法
前提是:1-两两配对
2-路径间不可能交叉
本题刚好满足

例题:插头DP
给你一个 n×m 的棋盘,有的格子是障碍,问共有多少条回路满足经过每个非障碍格子恰好一次。

如图,n=m=4,(1,1),(1,2) 是障碍,共有 2 条满足要求的回路。
输入格式
第一行包含两个整数 n,m。
接下来 n 行,每行包含一个长度为 m 的字符串,字符串中只包含
*和.,其中*表示障碍格子,.表示非障碍格子。
输出格式
输出一个整数,表示满足条件的回路数量。
数据范围
2 ≤ n,m ≤ 12
输入样例:
- 4 4
- **..
- ....
- ....
- ....
输出样例:
2
核心:枚举每个状态

提示:状态五在改变之前x,y均是1,但因为两条边不能交叉,所以两条出边必然连在一起,则x,y不再满足是路径的左端,所以不是1,而右边分别变为1,2
- #include<iostream>
- #include<cstring>
-
- using namespace std;
-
- typedef long long ll;
- const int N=50000,M=N*2+7;
-
- int n,m,end_x,end_y;
- int g[20][20],q[2][N],cnt[N];//q有效状态在哈希表下标,cnt有效数量
- int h[2][M];
- ll v[2][M];//方案数
-
- int find(int cur,int x)//开放寻址法
- {
- int t=x%M;
- while(h[cur][t]!=-1&&h[cur][t]!=x)
- if(++t==M)
- t=0;
- return t;
- }
-
- void insert(int cur,int state,ll w)//当前滚动插入state,数量是w
- {
- int t=find(cur,state);
- if(h[cur][t]==-1)
- {
- h[cur][t]=state,v[cur][t]=w;
- q[cur][++cnt[cur]]=t;
- }
- else
- v[cur][t]+=w;
- }
-
- int get(int state,int k)//求第k个格子的状态,实际求四进制的第k位数字
- {
- return state>>k*2&3;
- }
-
- int set(int k,int v)//构造四进制的第k位数字为v的数
- {
- return v*(1<<k*2);
- }
-
- int main()
- {
- cin>>n>>m;
- for(int i=1;i<=n;i++)
- {
- char str[20];
- scanf("%s",str+1);
- for(int j=1;j<=m;j++)
- {
- if(str[j]=='.')
- {
- g[i][j]=1;
- end_x=i,end_y=j;
- }
- }
- }
-
- ll res=0;
- memset(h,-1,sizeof h);
- int cur=0;//滚动数组
- insert(cur,0,1);//初始状态,方案数
- for(int i=1;i<=n;i++)
- {
- for(int j=1;j<=cnt[cur];j++)//处理换行
- {
- h[cur][q[cur][j]]<<=2;
- }
- for(int j=1;j<=m;j++)//枚举每个格子
- {
- int last=cur;//上一次滚动的
- cur^=1,cnt[cur]=0;
- memset(h[cur],-1,sizeof h[cur]);
- for(int k=1;k<=cnt[last];k++)//枚举有效状态
- {
- int state=h[last][q[last][k]];
- ll w=v[last][q[last][k]];
- int x=get(state,j-1),y=get(state,j);
-
- if(!g[i][j])
- {
- if(!x&&!y)
- insert(cur,state,w);
- }
- else if(!x&&!y)
- {
- if(g[i+1][j]&&g[i][j+1])
- insert(cur,state+set(j-1,1)+set(j,2),w);
- }
- else if(!x&&y)
- {
- if(g[i][j+1])
- insert(cur,state,w);
- if(g[i+1][j])
- insert(cur,state+set(j-1,y)-set(j,y),w);
- }
- else if(x&&!y)
- {
- if(g[i][j+1])
- insert(cur,state-set(j-1,x)+set(j,x),w);
- if(g[i+1][j])
- insert(cur,state,w);
- }
- else if(x==1&&y==1)
- {
- for(int u=j+1,s=1;;u++)
- {
- int z=get(state,u);
- if(z==1)
- s++;
- else if(z==2)
- {
- if(--s==0)
- {
- insert(cur,state-set(j-1,x)-set(j,y)-set(u,1),w);
- break;
- }
- }
- }
- }
- else if(x==2&&y==2)
- {
- for(int u=j-2,s=1;;u--)//找匹配
- {
- int z=get(state,u);
- if(z==2)
- s++;
- else if(z==1)
- {
- if(--s==0)
- {
- insert(cur,state-set(j-1,x)-set(j,y)+set(u,1),w);
- break;
- }
- }
- }
- }
- else if(x==2&&y==1)
- {
- insert(cur,state-set(j-1,x)-set(j,y),w);
- }
- else if(i==end_x&&j==end_y)
- res+=w;
- }
- }
- }
- cout<<res<<endl;
- }

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。