hdu 4856 Tunnels BFS+不回起点的TSP
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4856
注意到隧道是单向的
bfs求出距离以后套用TSP模板即可
注意日本人那本白书上的模板是最后要回到起点的
而本题并不回起点
具体的做法是建一个超级起点,跟图中每一个点都建花费为0的边,然后以之为起点跑一边即可
#include <cstring> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> #include <iostream> #include <cstdio> #include <stack> #include <vector> #include <queue> #include <map> #include <set> using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<int, int> P; const int maxn = 17; const int INF = 0x3f3f3f3f; int n, m; char a[maxn][maxn]; int b[maxn][2]; int c[maxn][2]; int d[maxn][maxn]; int dp[1 << maxn][maxn]; const int walk[][2] = {1, 0, 0, 1, -1, 0, 0, -1}; struct Node { int x, y; int s; }; bool vis[maxn][maxn]; void bfs(int u, int v) { memset(vis, 0, sizeof(vis)); queue<Node> que; Node cur; cur.x = c[u][0]; cur.y = c[u][1]; cur.s = 0; vis[cur.x][cur.y] = 1; que.push(cur); while(!que.empty()) { cur = que.front(); que.pop(); int x = cur.x; int y = cur.y; if(x == b[v][0] && y == b[v][1]) { d[u][v] = cur.s; return; } for(int i = 0; i < 4; i++) { int nx = x + walk[i][0]; int ny = y + walk[i][1]; if(0 <= nx && nx < n && 0 <= ny && ny < n && a[nx][ny] == '.' && vis[nx][ny] == 0) { vis[nx][ny] = 1; Node nxt = {nx, ny, cur.s+1}; que.push(nxt); } } } d[u][v] = INF; return; } int main() { //freopen("in.txt", "r", stdin); while(scanf("%d%d", &n, &m) == 2) { for(int i = 0; i < n; i++) scanf("%s", a[i]); for(int i = 0; i < m; i++) { scanf("%d%d%d%d", &b[i][0], &b[i][1], &c[i][0], &c[i][1]); b[i][0]--; b[i][1]--; c[i][0]--; c[i][1]--; } for(int i = 0; i < m; i++) for(int j = 0; j < m; j++) { if(i == j) continue; bfs(i, j); bfs(j, i); } for(int i = 0; i <= m; i++) d[i][i] = INF; for(int i = 0; i < m; i++) d[i][m] = d[m][i] = 0; int ans = INF; m++; for(int i = 0; i < 1 << m; i++) fill(dp[i], dp[i] + m, INF); dp[((1 << m) - 1)][m-1] = 0; for(int S = (1 << m) - 1; S >= 0; S--) for(int v = 0; v < m; v++) for(int u = 0; u < m; u++) if(!(S >> u & 1)) { dp[S][v] = min(dp[S][v], dp[S | 1 << u][u] + d[v][u]); /*if(S == 0 && dp[S][v] < minnum) minnum = dp[S][v];*/ } if(dp[0][m-1] != INF) printf("%d\n", dp[0][m-1]); else printf("-1\n"); } return 0; }