circuits
Time Limit: 30000/15000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 592 Accepted Submission(s): 175
Problem Description Given a map of N * M (2 <= N, M <= 12) , '.' means empty, '*' means walls. You need to build K circuits and no circuits could be nested in another. A circuit is a route connecting adjacent cells in a cell sequence, and also connect
the first cell and the last cell. Each cell should be exactly in one circuit. How many ways do we have?
Input The first line of input has an integer T, number of cases.
For each case:
The first line has three integers N M K, as described above.
Then the following N lines each has M characters, ‘.’ or ‘*’.
Output For each case output one lines.
Each line is the answer % 1000000007 to the case.
Sample Input
24 4 1**..............4 4 1................
Sample Output
26
Source2012 ACM/ICPC Asia Regional Tianjin Online
Recommendliuyiding 這題和hdu 1693 Eat the Trees類似只是限制的迴路的個數。所以在hashmap裡再加一個記錄迴路數的數組就行了。對於判斷是否有嵌套的情況就判斷當前格之前有多少個插頭。若是有奇數個。說明肯定有嵌套。畫畫圖就明白了。
#include<stdio.h>#include<string.h>#include<iostream>#include<algorithm>using namespace std;const int HASH=30007;//雜湊表的大小const int STATE=1000010;//狀態數const int MAXD=15;const int MOD=1000000007;int N,M,mac;//mac目標迴路數int code[MAXD],maze[MAXD][MAXD],mcod[MAXD];//編碼。和存地圖。最小標記法char s[20];struct HASHMAP//雜湊表結構{ int head[HASH],next[STATE],sz;//雜湊表頭指標模數相同的狀態用鏈表串連。方便狀態尋找和判重 long long f[STATE],state[STATE];//f記錄對應狀態的方法數。next指向模數相同的下一個狀態。state選項組。sz選項組總數 int circle[STATE]; void init()//雜湊表初始化函數 { sz=0; memset(head,-1,sizeof(head)); } void push(long long st,long long ans,int cir)//壓入狀態和方法數 { int i,h=st%HASH; for(i=head[h]; i!=-1; i=next[i]) if(st==state[i]&&cir==circle[i])//若狀態已經存在。方法數增加就行 { //注意要迴路數也相同才能算等效 f[i]+=ans; f[i]%=MOD; return; } f[sz]=ans;//存入新的可行狀態 state[sz]=st; circle[sz]=cir; next[sz]=head[h]; head[h]=sz++; }} hm[2];void decode(int *code,int m,long long st)//編碼從高位到低位m到0編碼。對應從左至右的插頭{ int i; for(i=m; i>=0; i--) { code[i]=st&7; st>>=3; }}long long encode(int *code,int m)//最小標記法解碼到st中{ int i,cnt=1; long long st=0; memset(mcod,-1,sizeof mcod); mcod[0]=0; for( i=0; i<=m; i++) { if(mcod[code[i]]==-1) mcod[code[i]]=cnt++; code[i]=mcod[code[i]]; st<<=3; st|=code[i]; } return st;}void init()//讀資料。初始化{ int i,j; memset(maze,0,sizeof maze); for(i=1; i<=N; i++) { scanf("%s",s+1); for( j=1; j<=M; j++) if(s[j]=='.') maze[i][j]=1; }}void dpblank(int i,int j,int cur)//處理可到格的情況{ int k,t,left,up,temp,cot; for(k=0; k<hm[cur].sz; k++) //遍曆j格出輪廓線的狀態進行狀態轉移 { if(hm[cur].circle[k]>mac) continue; decode(code,M,hm[cur].state[k]);//對狀態進行編碼 left=code[j-1];//擷取左插頭狀態 up=code[j];//擷取上插頭狀態 if(left&&up)//11 -> 00 { if(left==up)//形成迴路 { cot=0; for(t=0;t<j-1;t++)//判斷在當前格之前有多少插頭 if(code[t]) cot++; if(cot&1)//如果插頭數是奇數說明有嵌套的情況。自己畫畫就明白了 continue; code[j-1]=code[j]=0;//只能為0一個格子只能兩個插頭 hm[cur^1].push(encode(code,j==M?M-1:M),hm[cur].f[k],hm[cur].circle[k]+1);//壓入新狀態 } else { code[j-1]=code[j]=0; for(t=0; t<=M; t++) if(code[t]==up) { code[t]=left; break; } hm[cur^1].push(encode(code,j==M?M-1:M),hm[cur].f[k],hm[cur].circle[k]);//壓入新狀態 } } else if((!left&&up)||(left&&!up))//01 或 10 { if(up) temp=up; else temp=left; if(maze[i][j+1])//j==m時maze[i][j]為0也不用shift { code[j-1]=0; code[j]=temp; hm[cur^1].push(encode(code,M),hm[cur].f[k],hm[cur].circle[k]); } if(maze[i+1][j]) { code[j-1]=temp; code[j]=0; hm[cur^1].push(encode(code,j==M?M-1:M),hm[cur].f[k],hm[cur].circle[k]); } } else { if(maze[i][j+1]&&maze[i+1][j])//若j==m不會合法所以不用shift { code[j]=code[j-1]=13; hm[cur^1].push(encode(code,M),hm[cur].f[k],hm[cur].circle[k]); } } }}void dpblock(int i,int j,int cur)//處理不能到格的情況{ int k; for(k=0; k<hm[cur].sz; k++) //存入狀態均合法不用判斷 { decode(code,M,hm[cur].state[k]);//先編碼 code[j-1]=code[j]=0;//肯定不能用插頭 hm[cur^1].push(encode(code,j==M?M-1:M),hm[cur].f[k],hm[cur].circle[k]); }}void solve(){ int i,j,cur=0; long long ans=0; hm[cur].init();//cur用於滾動數組。節約空間。cur存當前格上插頭和左插頭情況。cur^1用於記錄轉移出的新狀態即下一格 hm[cur].push(0,1,0); for(i=1; i<=N; i++) for(j=1; j<=M; j++) { hm[cur^1].init();//初始化 if(maze[i][j])dpblank(i,j,cur); else dpblock(i,j,cur); cur^=1; } for(i=0; i<hm[cur].sz; i++) if(hm[cur].circle[i]==mac) ans+=hm[cur].f[i]; printf("%I64d\n",ans);}int main(){ int cas; scanf("%d",&cas); while(cas--) { scanf("%d%d%d",&N,&M,&mac); init(); solve(); } return 0;}