Descriprion
给出$n imes m$ 的方格,有些格子不能铺线,其它格子必须铺,形成一个闭合回路。问有多少种铺法?
Solution
使用括号表示法记录状态,记1为 '(' ,2为 ')' ,0为无插头,分8种情况讨论:
- 1:当前格子有障碍,此时必须下插头和右插头为0,转移后状态不变
- 2:当前格子下插头和右插头为0,转移后右插头为1,下插头为2
- 3:当前格子有右插头,无下插头,转移后右插头位置不变或向右移动一位
- 4:当前格子有下插头,无右插头,转移后下插头位置不变或向左移动一位
- 5:当前格子下插头和右插头为1,转移后从当前格子向右首个不匹配的2变为1
- 6:当前格子下插头和右插头为2,转移后从当前格子向左首个不匹配的1变为2
- 7:当前格子右插头为2,左插头为1,转移后删除两插头
- 8:当前格子右插头为1,左插头为2,此时必须为最后一个可访问格子,更新总答案
优化:使用链表存储状态为模数同余系的状态;滚动数组
#include<iostream> #include<cstring> #include<cstdio> using namespace std; int n,m,map[15][15],endx,endy,bits[15],pre=1,cur,tots[2],state[2][600000],head[600000],tot; const int mod=590027; long long ans,dp[2][600000]; struct Edge { int to,nxt; }edge[600000]; inline int read() { int f=1,w=0; char ch=0; while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { w=(w<<1)+(w<<3)+ch-'0'; ch=getchar(); } return f*w; } void insert(int sta,long long val) { int key=sta%mod; for(int i=head[key];i;i=edge[i].nxt) { if(state[cur][edge[i].to]==sta) { dp[cur][edge[i].to]+=val; return; } } tots[cur]++; state[cur][tots[cur]]=sta; dp[cur][tots[cur]]=val; edge[++tot]=(Edge){tots[cur],head[key]}; head[key]=tot; } void DP() { tots[cur]=1; state[cur][1]=0; dp[cur][1]=1; for(int i=1;i<=n;i++) { for(int j=1;j<=tots[cur];j++) { state[cur][j]<<=2; } for(int j=1;j<=m;j++) { tot=0; memset(head,0,sizeof(head)); swap(cur,pre); tots[cur]=0; int nowsta=0,d=0,r=0; long long nowans=0; for(int k=1;k<=tots[pre];k++) { nowsta=state[pre][k]; nowans=dp[pre][k]; d=(nowsta>>bits[j])%4; r=(nowsta>>bits[j-1])%4; if(!map[i][j]) { if(!d&&!r) { insert(nowsta,nowans); } } else if(!d&&!r) { if(map[i+1][j]&&map[i][j+1]) { insert(nowsta+(1<<bits[j-1])+2*(1<<bits[j]),nowans); } } else if(!d&&r) { if(map[i+1][j]) { insert(nowsta,nowans); } if(map[i][j+1]) { insert(nowsta-r*(1<<bits[j-1])+r*(1<<bits[j]),nowans); } } else if(!r&&d) { if(map[i][j+1]) { insert(nowsta,nowans); } if(map[i+1][j]) { insert(nowsta-d*(1<<bits[j])+d*(1<<bits[j-1]),nowans); } } else if(r==1&&d==1) { int cnt=1; for(int l=j+1;l<=m;l++) { if((nowsta>>bits[l])%4==1) { cnt++; } else if((nowsta>>bits[l])%4==2) { cnt--; } if(!cnt) { insert(nowsta-(1<<bits[j-1])-(1<<bits[j])-(1<<bits[l]),nowans); break; } } } else if(r==2&&d==2) { int cnt=1; for(int l=j-2;l>=0;l--) { if((nowsta>>bits[l])%4==1) { cnt--; } else if((nowsta>>bits[l])%4==2) { cnt++; } if(!cnt) { insert(nowsta-2*(1<<bits[j-1])-2*(1<<bits[j])+(1<<bits[l]),nowans); break; } } } else if(r==2&&d==1) { insert(nowsta-2*(1<<bits[j-1])-(1<<bits[j]),nowans); } else { if(i==endx&&j==endy) { ans+=nowans; } } } } } } int main() { n=read(); m=read(); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { char ch=0; while(ch!='.'&&ch!='*') { ch=getchar(); } if(ch=='.') { map[i][j]=1; endx=i; endy=j; } } } for(int i=1;i<=14;i++) { bits[i]=i<<1; } DP(); printf("%lld ",ans); return 0; }