开学忙成狗,刷题慢如蜗牛……
【题目大意】
给出一个m*n的矩阵里面有一些格子为障碍物,一些格子只能上下通行,一些格子只能左右通行,一些格子上下左右都能通行。问经过所有非障碍格子的哈密顿回路个数。
【思路】
和BZOJ1814差不多,增加几个比较简单的判断即可。详见代码。
【错误点】
一开始我把三种可通行的情况写在一起,有点混乱了……拆开成3个函数就好啦!
下次注意程序的可读性。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<vector> 6 using namespace std; 7 typedef long long ll; 8 const int MAXN=14; 9 const int HASH=30007; 10 int ex,ey; 11 int m,n; 12 int maze[MAXN][MAXN]; 13 int code[MAXN],ch[MAXN]; 14 struct HashMap 15 { 16 vector<int> hash[HASH];//存储f和state的下标 17 vector<ll> f,state;//存储对应的方案数和状态 18 void init() 19 { 20 for (int i=0;i<HASH;i++) vector<int>().swap(hash[i]); 21 vector<ll>().swap(f); 22 vector<ll>().swap(state); 23 } 24 void push(ll st,ll ans) 25 { 26 int h=st%HASH; 27 for (int i=0;i<hash[h].size();i++) 28 { 29 int now=hash[h][i]; 30 if (state[now]==st)//如果已经存储了当前状态,直接累加 31 { 32 f[now]+=ans; 33 return; 34 } 35 } 36 //如果没有存储过当前状态,累加 37 state.push_back(st); 38 f.push_back(ans); 39 hash[h].push_back(state.size()-1); 40 } 41 }dp[2]; 42 43 void decode(ll st) 44 { 45 memset(code,0,sizeof(code)); 46 for (int i=n;i>=0;i--) 47 { 48 code[i]=st&7;//每三位代表一个信息 49 st>>=3; 50 } 51 } 52 53 ll encode() 54 //用最小表示法重新编码 55 { 56 int cnt=1; 57 memset(ch,-1,sizeof(ch)); 58 ch[0]=0; 59 long long st=0; 60 for (int i=0;i<=n;i++) 61 { 62 if (ch[code[i]]==-1) ch[code[i]]=cnt++; 63 code[i]=ch[code[i]]; 64 st<<=3; 65 st|=code[i]; 66 } 67 return st; 68 } 69 70 void shift() 71 { 72 for (int i=n;i>0;i--) code[i]=code[i-1]; 73 code[0]=0; 74 } 75 76 77 void dpblank(int i,int j,int cur) 78 { 79 for (int k=0;k<dp[1-cur].state.size();k++) 80 { 81 decode(dp[1-cur].state[k]); 82 int left=code[j-1];//左插头 83 int up=code[j];//上插头 84 85 /*如果上下插头都没有*/ 86 if (!left && !up) 87 { 88 if (maze[i][j+1] && maze[i+1][j]) 89 { 90 code[j-1]=code[j]=MAXN-1; 91 //这里只要随便设置一个大数即可 92 93 //【attention】这里千万不可以设置成MAXN,否则ch数组会抱★★★★★★★★ 94 95 //因为encode会重新用最小表示法编码 96 dp[cur].push(encode(),dp[1-cur].f[k]); 97 } 98 } 99 100 /*只有上插头或者只有左插头*/ 101 if ((left&&(!up))||((!left)&&up)) 102 { 103 104 int t=left|up; 105 if (maze[i][j+1])//右边没有障碍 106 { 107 code[j-1]=0; 108 code[j]=t; 109 dp[cur].push(encode(),dp[1-cur].f[k]); 110 } 111 if (maze[i+1][j])//下面没有障碍 112 { 113 code[j-1]=t; 114 code[j]=0; 115 if (j==n) shift(); 116 dp[cur].push(encode(),dp[1-cur].f[k]); 117 } 118 } 119 120 /*上插头和右插头都有*/ 121 if (left && up) 122 { 123 if (left==up) 124 { 125 if (i==ex && j==ey) 126 { 127 code[j-1]=code[j]=0; 128 if (j==n) shift(); 129 dp[cur].push(encode(),dp[1-cur].f[k]); 130 } 131 } 132 else 133 { 134 code[j-1]=code[j]=0; 135 for (int t=0;t<=n;t++) 136 if (code[t]==up) code[t]=left; 137 if (j==n) shift(); 138 dp[cur].push(encode(),dp[1-cur].f[k]); 139 } 140 } 141 } 142 } 143 144 void DpHorizon(int cur,int i,int j)//只能水平走 145 { 146 for (int k=0;k<dp[1-cur].state.size();k++) 147 { 148 decode(dp[1-cur].state[k]); 149 int left=code[j-1],up=code[j]; 150 151 if(!up && left&& maze[i][j+1]!=0 && maze[i][j+1]!=3&& j!=n&&j!=1) //右边不是障碍物,也能够水平走,并且不是最右边 152 { 153 code[j-1]=0; 154 code[j]=left; 155 dp[cur].push(encode(),dp[1-cur].f[k]); 156 } 157 } 158 159 } 160 161 void DpVertical(int cur,int i,int j)//只能竖直走 162 { 163 for (int k=0;k<dp[1-cur].state.size();k++) 164 { 165 decode(dp[1-cur].state[k]); 166 int left=code[j-1],up=code[j]; 167 168 if(up && !left && maze[i+1][j]!=0 && maze[i+1][j]!=2&&i!=m&&i!=1)//下边不是障碍物,也能够竖直走 169 { 170 code[j-1]=up; 171 code[j]=0; 172 if(j==n)shift(); 173 dp[cur].push(encode(),dp[1-cur].f[k]); 174 } 175 } 176 177 } 178 179 void dpblock(int i,int j,int cur) 180 { 181 int k=0; 182 for (int k=0;k<dp[1-cur].state.size();k++) 183 { 184 decode(dp[1-cur].state[k]); 185 code[j-1]=code[j]=0; 186 if (j==n) shift(); 187 dp[cur].push(encode(),dp[1-cur].f[k]); 188 } 189 } 190 191 void solve() 192 { 193 int cur=0; 194 ll ans=0; 195 dp[cur].init(); 196 dp[cur].push(0,1);//DP数组初始化 197 for (int i=1;i<=m;i++) 198 for (int j=1;j<=n;j++) 199 { 200 cur^=1; 201 dp[cur].init(); 202 if (maze[i][j]==1) dpblank(i,j,cur); 203 else if (maze[i][j]==0) dpblock(i,j,cur); 204 else if (maze[i][j]==2)DpHorizon(cur,i,j); 205 else DpVertical(cur,i,j); 206 } 207 for (int i=0;i<dp[cur].state.size();i++) 208 ans+=dp[cur].f[i]; 209 printf("%lld",ans); 210 } 211 212 213 void init() 214 { 215 scanf("%d%d",&m,&n); 216 for (int i=1;i<=m;i++) 217 { 218 char str[MAXN]; 219 scanf("%s",str); 220 for (int j=1;j<=n;j++) 221 { 222 if (str[j-1]=='#') maze[i][j]=0; 223 if (str[j-1]=='.') maze[i][j]=1; 224 if (str[j-1]=='-') maze[i][j]=2; 225 if (str[j-1]=='|') maze[i][j]=3; 226 if (str[j-1]!='#') ex=i,ey=j; 227 } 228 } 229 } 230 231 int main() 232 { 233 234 init(); 235 if (ex==0) puts("0");//如果没有一个是空格的话直接输出0 236 else solve(); 237 238 }