HDU-4856 Tunnels (BFS+状压DP)
Problem Description
Bob is travelling in Xi’an. He finds many secret tunnels beneath the city. In his eyes, the city is a grid. He can’t enter a grid with a barrier. In one minute, he can move into an adjacent grid with no barrier. Bob is full of curiosity and he wants to visit all of the secret tunnels beneath the city. To travel in a tunnel, he has to walk to the entrance of the tunnel and go out from the exit after a fabulous visit. He can choose where he starts and he will travel each of the tunnels once and only once. Now he wants to know, how long it will take him to visit all the tunnels (excluding the time when he is in the tunnels).
Input
The input contains mutiple testcases. Please process till EOF.
For each testcase, the first line contains two integers N (1 ≤ N ≤ 15), the side length of the square map and M (1 ≤ M ≤ 15), the number of tunnels.
The map of the city is given in the next N lines. Each line contains exactly N characters. Barrier is represented by “#” and empty grid is represented by “.”.
Then M lines follow. Each line consists of four integers x1, y1, x2, y2, indicating there is a tunnel with entrence in (x1, y1) and exit in (x2, y2). It’s guaranteed that (x1, y1) and (x2, y2) in the map are both empty grid.
For each testcase, the first line contains two integers N (1 ≤ N ≤ 15), the side length of the square map and M (1 ≤ M ≤ 15), the number of tunnels.
The map of the city is given in the next N lines. Each line contains exactly N characters. Barrier is represented by “#” and empty grid is represented by “.”.
Then M lines follow. Each line consists of four integers x1, y1, x2, y2, indicating there is a tunnel with entrence in (x1, y1) and exit in (x2, y2). It’s guaranteed that (x1, y1) and (x2, y2) in the map are both empty grid.
Output
For each case, output a integer indicating the minimal time Bob will use in total to walk between tunnels.
If it is impossible for Bob to visit all the tunnels, output -1.
If it is impossible for Bob to visit all the tunnels, output -1.
Sample Input
5 4
....#
...#.
.....
.....
.....
2 3 1 4
1 2 3 5
2 3 3 1
5 4 2 1
Sample Output
7
题目大意:在一张nxn(n<16)的图中,"."表示空白区域,"#"表示障碍,每次移动的方向是上下左右之一,每移动一次耗时加1。有m条已知进口和出口的隧道,在隧道中移动不花时间。问要游览完所有的隧道最少需要的时间是多少?顺序自选。
题目分析:一看数据规模那么小,就想到是状压DP了。但要用BFS预处理出两两隧道之间的距离(起始隧道的出口与终止隧道的进口的距离)。定义状态dp(i,j)表示已经走过的隧道集合为i,并且当前在j位置时已经花掉的最小时间。则状态转移方程为dp(i|(1<<k),k)=min(dp(i|(1<<k),k),dp(i,j)+dist(j,k))。
代码如下:
# include<iostream> # include<cstdio> # include<queue> # include<cstring> # include<algorithm> using namespace std; const int INF=100000; struct TT { int sx,sy,ex,ey; }; struct node { int x,y,t; node(int _x,int _y,int _t):x(_x),y(_y),t(_t){} }; TT t[15]; char mp[20][20]; int dist[20][20]; int vis[20][20],n,m,dp[1<<15][15]; int d[4][2]={{0,-1},{0,1},{-1,0},{1,0}}; int bfs(int sx,int sy,int ex,int ey) { queue<node>q; memset(vis,0,sizeof(vis)); vis[sx][sy]=1; q.push(node(sx,sy,0)); while(!q.empty()) { node u=q.front(); q.pop(); if(u.x==ex&&u.y==ey) return u.t; for(int i=0;i<4;++i){ int nx=u.x+d[i][0],ny=u.y+d[i][1]; if(nx>=1&&nx<=n&&ny>=1&&ny<=n&&!vis[nx][ny]&&mp[nx][ny]!='#'){ vis[nx][ny]=1; q.push(node(nx,ny,u.t+1)); } } } return INF; } void init() { for(int i=0;i<m;++i) for(int j=0;j<m;++j) dist[i][j]=bfs(t[i].ex,t[i].ey,t[j].sx,t[j].sy); } void DP() { int tot=1<<m; for(int i=0;i<tot;++i) for(int j=0;j<m;++j) dp[i][j]=INF; for(int i=0;i<m;++i) dp[1<<i][i]=0; for(int i=1;i<tot;++i){ for(int j=0;j<m;++j){ if(i&(1<<j)) continue; int sta=i|(1<<j); for(int k=0;k<m;++k){ if(i&(1<<k)) dp[sta][j]=min(dp[sta][j],dp[i][k]+dist[k][j]); } } } int ans=INF; for(int i=0;i<m;++i) ans=min(ans,dp[tot-1][i]); if(ans==INF) printf("-1\n"); else printf("%d\n",ans); } int main() { while(~scanf("%d%d",&n,&m)) { for(int i=1;i<=n;++i) scanf("%s",mp[i]+1); for(int i=0;i<m;++i) scanf("%d%d%d%d",&t[i].sx,&t[i].sy,&t[i].ex,&t[i].ey); init(); DP(); } return 0; }