hdu-4856 Tunnels 状压DP
http://acm.hdu.edu.cn/showproblem.php?pid=4856
有若干管道,每个管道有且只能走一次,而地图可以随意走。
那么可以先处理每个管道间的最短路(不要考虑借助其他管道的情况,因为随后我们用压位的方式可以很轻松地处理不走重复管道的问题,这里不应该引入过多干扰)。
随后我们把每个管道是否访问看作01序列,dp[i][j]看着当前处于j号管道,访问状态为i。然后预先加入当且访问一个管道的m个状态,做bfs即可(很多人做了三重循环,个人不太会那么犀利的操作,只会bfs直观一点hhh,不过两个bfs搞得代码很丑就是了)。
#include <iostream> #include <string> #include <queue> #include <cstring> using namespace std; const int N=1005; const int inf=99999999; int n,m; string mp[20]; int vis[20][20]; struct p { int x,y; }; p in[20],ou[20]; int d[20][20]; struct node { int s; p po; }; int dir[4][2]={1,0,-1,0,0,1,0,-1}; bool ok(p px) { if(px.x<0||px.y<0)return 0; if(px.x>=n||px.y>=n)return 0; if(vis[px.y][px.x]) return 0; if(mp[px.y][px.x]=='#')return 0; return 1; } void bfs(int np) { queue<node> q; node ii; ii.s=0; ii.po=ou[np]; q.push(ii); memset(vis,0,sizeof vis); vis[ii.po.y][ii.po.x]=1; d[np][np]=0; while(!q.empty()) { node now=q.front(); q.pop(); for(int i=0;i<m;i++) { if(i==np)continue; if(now.po.x==in[i].x&&now.po.y==in[i].y) d[np][i]=now.s; } for(int i=0;i<4;i++) { node nx=now; nx.s++; nx.po.x+=dir[i][0]; nx.po.y+=dir[i][1]; if(ok(nx.po)) { vis[nx.po.y][nx.po.x]=1; q.push(nx); } } } } int dp[40000][20]; int numid[20]; struct dpx { int d; int po; dpx(int dd,int pp) { d=dd; po=pp; } }; int main() { cin.sync_with_stdio(false); while(cin>>n>>m) { for(int i=0;i<n;i++) cin>>mp[i]; for(int i=0;i<m;i++) { cin>>in[i].y>>in[i].x>>ou[i].y>>ou[i].x; in[i].x--; in[i].y--; ou[i].x--; ou[i].y--; } for(int i=0;i<m;i++) for(int j=0;j<m;j++) d[i][j]=inf; for(int i=0;i<m;i++) bfs(i); for(int i=0;i<(1<<m);i++) for(int j=0;j<m;j++) dp[i][j]=inf; int dx=1; queue<dpx> q; int ad=0; for(int i=0;i<m;i++) { ad+=dx; dp[dx][i]=0; numid[i]=dx; q.push(dpx(dx,i)); dx<<=1; } while(!q.empty()) { dpx now=q.front(); q.pop(); for(int i=0;i<m;i++) { if((now.d&numid[i])==0) { dpx nx=now; nx.d+=numid[i]; nx.po=i; if(dp[nx.d][nx.po]>dp[now.d][now.po]+d[now.po][nx.po]) { dp[nx.d][nx.po]=dp[now.d][now.po]+d[now.po][nx.po]; q.push(nx); } } } } int ans=inf; for(int i=0;i<m;i++) ans=min(ans,dp[(1<<m)-1][i]); if(ans>=inf)cout<<-1<<endl; else cout<<ans<<endl; } return 0; }