POJ 1161 - Walls
http://poj.org/problem?id=1161
概要
N 個の街があり,図のように M 個の領域(外側の領域も含む)に区切られている.
街 t から領域 r へ移動するのに横切る必要がある壁の数を f(t, r) で表わしたとき, 与えられた L 個の街 t[1], ..., t[L] について,f(t[1], r) + ... + f(t[L], r) の r に関する最小値を答える.
制約
- 3 <= N <= 250
- 2 <= M <= 200
- 1 <= L <= 30, L <= N
解法
領域同士の接続関係を表わすグラフをがんばって作ってワーシャル・フロイドした後,r に関する最小値を計算する.
poj/1161.cc1 #include <cstdio> 2 #include <vector> 3 using namespace std; 4 5 int main() 6 { 7 int M, N, L; 8 scanf("%d %d %d", &M, &N, &L); 9 vector<int> clubs(L); 10 vector<vector<int> > adj(N); 11 for (int i = 0; i < L; i++) { 12 scanf("%d", &clubs[i]); 13 --clubs[i]; 14 } 15 16 static const int INF = 10000000; 17 vector<vector<int> > dist(M, vector<int>(M, INF)); 18 for (int i = 0; i < M; i++) { 19 dist[i][i] = 0; 20 } 21 vector<int> walls(N*N, -10); 22 for (int i = 0; i < M; i++) { 23 int T; 24 scanf("%d", &T); 25 vector<int> towns(T); 26 for (int j = 0; j < T; j++) { 27 scanf("%d", &towns[j]); 28 --towns[j]; 29 adj[towns[j]].push_back(i); 30 } 31 for (int j = 0; j < T; j++) { 32 int n = towns[j], m = towns[(j+1)%T]; 33 if (n > m) { 34 swap(n, m); 35 } 36 const int w = n*N + m; 37 if (walls[w] < 0) { 38 walls[w] = i; 39 } else { 40 const int u = walls[w]; 41 dist[u][i] = dist[i][u] = 1; 42 } 43 } 44 } 45 46 for (int k = 0; k < M; k++) { 47 for (int i = 0; i < M; i++) { 48 for (int j = 0; j < M; j++) { 49 dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]); 50 } 51 } 52 } 53 int ans = INF; 54 for (int i = 0; i < M; i++) { 55 int s = 0; 56 for (vector<int>::const_iterator it = clubs.begin(); it != clubs.end(); ++it) { 57 int x = INF; 58 for (vector<int>::const_iterator jt = adj[*it].begin(); jt != adj[*it].end(); ++jt) { 59 x = min(x, dist[i][*jt]); 60 } 61 s += x; 62 } 63 ans = min(ans, s); 64 } 65 printf("%d\n", ans); 66 67 return 0; 68 }