bzoj3125: CITY 题解
3125: CITY
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 486 Solved: 213
[Submit][Status][Discuss]
Description
小明和小华要参加NOI,踏上了去X市的火车。
小明望着窗外的田野,大楼,工厂缓缓后退,在思考着什么。
这时,对面的小华拿出手机对着他说:“看!我们在这个位置!”
小明望着手机上显示的地图,城市被接到分割成各个方块,而自己所在的点在慢慢移动。
他突然意识到自己甚至还没游历过这个自己所在的小城市,学校和家貌以及之间来回的道路似乎成了这个小城的唯一印象。
若我把它们全部走一圈,可能要仔细计划下吧……不,那么多方案,其实我应该早能做到了吧……小明在心里对自己说。
Input
第一行有两个数N, M表示地图被分割成N*M个块,接下来有N行,每行有M个字符。
. 表示这个块可以通过
- 表示这个块只可以左右通过
| 表示这个块只可以上下通过
# 表示这个块不能通过
(从每个块只能走到其上下左右相邻的四个块)
Output
一个数,表示小明把所以可以通过的块都经过且只经过一次并回到原地的方案数。
Sample Input
Sample 1
2 2
..
..
Sample 2
Input:
4 4
....
..-.
....
....
2 2
..
..
Sample 2
Input:
4 4
....
..-.
....
....
Sample Output
Output 1
1
Output 2
1
1
Output 2
1
HINT
数据范围: 0 < N, M < 13 不保证答案在long 范围之内
Source
联赛后第一次写题解……
这道题可以说得上是插头DP裸题了,话说最早接触插头DP是在学基础状压的时候误打误撞看到了CDQ的论文,差点入坑,然而最后我还是得入一下。
这道题比较特殊的就是‘-’ ‘|’这两个设定,但其实也很容易,我们只要在转移的时候进行特判,‘-’只能接左插头,‘|’只能接上插头。其余转移同理。但是要注意的是由于许多转移代码大体结构一样,可以直接复制粘贴,但是细节还是要去检查一下,我因为特判粘贴后位置改变却没发现调了两个小时。
1 #include <iostream> 2 #include <cstdlib> 3 #include <cstdio> 4 #include <cstring> 5 #include <algorithm> 6 #include <cmath> 7 #define N 15 8 using namespace std; 9 int n,m,ma[N][N],zz,tot[1594330]; 10 char bb[N]; 11 int xp[N],b[1594330],dl[1594330]; 12 long long f[2][1594330],ans; 13 bool check(int x,int t,int sum) 14 { 15 if(sum<0) return 0; 16 if(x==m+1) 17 return sum==0; 18 if(b[t/xp[x]]==1) return check(x+1,t,sum+1); 19 else if(b[t/xp[x]]==2) return check(x+1,t,sum-1); 20 else return check(x+1,t,sum); 21 } 22 int main() 23 { 24 int nn,mm; 25 scanf("%d%d",&n,&m); 26 for(int i=1;i<=n;i++) 27 { 28 scanf("%s",bb+1); 29 for(int j=1;j<=m;j++) 30 { 31 if(bb[j]=='.') ma[i][j]=1,nn=i,mm=j; 32 else if(bb[j]=='-') ma[i][j]=2,nn=i,mm=j; 33 else if(bb[j]=='|') ma[i][j]=3,nn=i,mm=j; 34 } 35 } 36 xp[0]=1; 37 for(int i=1;i<=m+1;i++) xp[i]=xp[i-1]*3; 38 for(int i=0;i<xp[m+1];i++) b[i]=i%3; 39 for(int i=0;i<xp[m+1];i++) 40 { 41 if(check(0,i,0)) 42 { 43 zz++; 44 tot[zz]=i; 45 dl[i]=zz; 46 } 47 } 48 int now=1,la=0; 49 f[1][1]=1; 50 for(int i=1;i<=n;i++) 51 { 52 for(int j=1;j<=m;j++) 53 { 54 la^=1,now^=1; 55 memset(f[now],0,sizeof(f[now])); 56 int p,q,x=xp[j-1],y=xp[j],t; 57 for(int k=1;k<=zz;k++) 58 { 59 p=b[tot[k]/x],q=b[tot[k]/y]; 60 t=tot[k]-p*x-q*y; 61 if(ma[i][j]) 62 { 63 if(!p&&!q) 64 { 65 if(ma[i][j]==1&&dl[t+x+(y<<1)]) f[now][dl[t+x+(y<<1)]]+=f[la][k]; 66 } 67 else if(!q) 68 { 69 if(ma[i][j]!=3) 70 { 71 if(j!=m&&dl[t+(y<<(p-1))]) f[now][dl[t+(y<<(p-1))]]+=f[la][k]; 72 if(i!=n&&ma[i][j]==1&&dl[t+(x<<(p-1))]) f[now][dl[t+(x<<(p-1))]]+=f[la][k]; 73 } 74 } 75 else if(!p) 76 { 77 if(ma[i][j]!=2) 78 { 79 if(j!=m&&ma[i][j]==1&&dl[t+(y<<(q-1))]) f[now][dl[t+(y<<(q-1))]]+=f[la][k]; 80 if(i!=n&&dl[t+(x<<(q-1))]) f[now][dl[t+(x<<(q-1))]]+=f[la][k]; 81 } 82 } 83 else if(p==1&&q==2) 84 { 85 if(!t&&i==nn&&j==mm) ans+=f[la][k]; 86 } 87 else if(p==2&&q==1) 88 { 89 if(ma[i][j]==1) 90 { 91 if(dl[t]) f[now][dl[t]]+=f[la][k]; 92 } 93 } 94 else if(p==1&&q==1) 95 { 96 if(ma[i][j]==1) 97 { 98 int u,tmp; 99 for(u=j+1,tmp=0;u<=m&&tmp>=0;tmp+=(b[t/xp[u]]==1)-(b[t/xp[u]]==2),u++); 100 u--; 101 if(t-xp[u]<0) continue; 102 if(dl[t-xp[u]]) f[now][dl[t-xp[u]]]+=f[la][k]; 103 } 104 } 105 else if(p==2&&q==2) 106 { 107 if(ma[i][j]==1) 108 { 109 int u,tmp; 110 for(u=j-2,tmp=0;u>0&&tmp>=0;tmp+=(b[t/xp[u]]==2)-(b[t/xp[u]]==1),u--); 111 u++; 112 if(dl[t+xp[u]]) f[now][dl[t+xp[u]]]+=f[la][k]; 113 } 114 } 115 } 116 else 117 { 118 if(!p&&!q&&dl[t]) f[now][dl[t]]+=f[la][k]; 119 } 120 } 121 } 122 for(int j=zz;j>=1;j--) 123 { 124 if(b[tot[j]]==0) 125 { 126 if(dl[tot[j]/3]) f[now][j]=f[now][dl[tot[j]/3]]; 127 else f[now][j]=0; 128 } 129 else f[now][j]=0; 130 } 131 } 132 printf("%lld\n",ans); 133 return 0; 134 }