http://poj.org/problem?id=1739
题意:n×m的棋盘,'#'是障碍,'.'是空白,求左下角走到右下角且走过所有空白格子的方案数。(n,m<=8)
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; #define BIT(a,b) ((a)<<((b)<<1)) #define CLR(a,b) (a^=((a)&BIT(3,b))) #define GET(a,b) (((a)>>((b)<<1))&3) int n, m, all, lastx, lasty; bool mp[12][12]; int find(int col, int flag, int s) { int sum=0; if(flag==0) { for(int i=col; i>=0; --i) { int k=GET(s, i); if(k==1) --sum; if(k==2) ++sum; if(!sum) return i; } } else { for(int i=col; i<=m; ++i) { int k=GET(s, i); if(k==1) ++sum; if(k==2) --sum; if(!sum) return i; } } return -1; } bool next(int s, int row, int col, bool U, bool D, bool L, bool R, int &T) { if((col==0 && L) || (col==m-1 && R)) return 0; if((row==0 && U) || (row==n-1 && D)) return 0; if((D && mp[row+1][col]) || (R && mp[row][col+1])) return 0; int l=GET(s, col), u=GET(s, col+1), d=0, r=0; if((!l && L) || (!u && U) || (l && !L) || (u && !U)) return 0; T=s; CLR(T, col); CLR(T, col+1); if(!l && !u) { if(D && R) d=1, r=2; } else if(l && u) { if(l==1 && u==1) { int pos=find(col+1, 1, s); CLR(T, pos); T|=BIT(1, pos); } else if(l==2 && u==2) { int pos=find(col, 0, s); CLR(T, pos); T|=BIT(2, pos); } else if(l==1 && u==2) { if(row!=lastx || col!=lasty) return 0; } } else if(l && !u) { if(D) d=l; if(R) r=l; } else if(!l && u) { if(D) d=u; if(R) r=u; } T|=BIT(d, col); T|=BIT(r, col+1); if(col==m-1) T<<=2, T&=all; //printf("t:"); print(T); puts(""); return 1; } struct H { static const int M=1000007; struct E { int next, to; }e[M]; int head, cnt, hash[M]; ll sum[M]; H() { memset(hash, -1, sizeof hash); memset(sum, 0, sizeof sum); cnt=head=0; } bool find(int x, int &pos) { pos=x%M; while(1) { if(hash[pos]==x) return 0; else if(hash[pos]==-1) break; ++pos; if(pos==M) pos=0; } hash[pos]=x; return 1; } void ins(int t, ll d) { int pos; if(!find(t, pos)) { sum[pos]+=d; return; } e[++cnt].next=head; head=cnt; e[cnt].to=pos; sum[pos]=d; } void clr() { for(int i=head; i; i=e[i].next) hash[e[i].to]=-1, sum[e[i].to]=0; head=0; cnt=0; } }T1, T2; ll bfs() { H *q1=&T1, *q2=&T2; q1->clr(); q1->ins(0, 1); for(int row=0; row<n; ++row) for(int col=0; col<m; ++col) { q2->clr(); for(int i=q1->head; i; i=q1->e[i].next) { ll sum=q1->sum[q1->e[i].to]; int s=q1->hash[q1->e[i].to], t; if(mp[row][col]) { if(next(s, row, col, 0, 0, 0, 0, t)) q2->ins(t, sum); } else { if(next(s, row, col, 1, 1, 0, 0, t)) q2->ins(t, sum); if(next(s, row, col, 1, 0, 1, 0, t)) q2->ins(t, sum); if(next(s, row, col, 1, 0, 0, 1, t)) q2->ins(t, sum); if(next(s, row, col, 0, 1, 1, 0, t)) q2->ins(t, sum); if(next(s, row, col, 0, 1, 0, 1, t)) q2->ins(t, sum); if(next(s, row, col, 0, 0, 1, 1, t)) q2->ins(t, sum); } } swap(q1, q2); } ll ans=0; for(int i=q1->head; i; i=q1->e[i].next) ans+=q1->sum[q1->e[i].to]; return ans; } int main() { char s[20]; while(scanf("%d%d", &n, &m), n|m) { for(int i=2; i<n+2; ++i) { scanf("%s", s+2); for(int j=2; j<m+2; ++j) if(s[j]=='#') mp[i][j]=1; else mp[i][j]=0; } n+=2; m+=4; for(int i=0; i<n; ++i) mp[i][1]=mp[i][m-2]=1; for(int i=0; i<m; ++i) mp[1][i]=1; for(int i=0; i<m; ++i) mp[0][i]=0; for(int i=0; i<n; ++i) mp[i][0]=mp[i][m-1]=0; mp[n-1][1]=mp[n-1][m-2]=0; lastx=n-1; lasty=m-1; all=BIT(1, m+1)-1; printf("%lld ", bfs()); } return 0; }
模板题...
将图用墙先封起来,然后开一条小路从左下角旋转到右下角,然后就是裸的求简单回路的问题辣...正确性很显然吧...