Codeforces Round #349 (Div. 1) B. World Tour 最短路+暴力枚举
题目链接:
http://www.codeforces.com/contest/666/problem/B
题意:
给你n个城市,m条单向边,求通过最短路径访问四个不同的点能获得的最大距离,答案输出一个满足条件的四个点。
题解:
首先预处理出任意两点的最短距离,用队列优化的spfa跑:O(n*n*logn)
现依次访问四个点:v1,v2,v3,v4
我们可以枚举v2,v3,然后求出v2的最远点v1,v3的最远点v4,为了保证这四个点的不同,直接用最远点会错,v1,v4相同时还要考虑次最远点来替换,反正解肯定是在离v2最远的三个点里面,在离v3最远的三个点里面,这个可以暴力枚举(3*3)。
1 #include<iostream> 2 #include<cstdio> 3 #include<vector> 4 #include<queue> 5 #include<algorithm> 6 using namespace std; 7 8 const int maxn = 3e3 + 10; 9 const int INF = 0x3f3f3f3f; 10 11 vector<int> G[maxn]; 12 int mat[maxn][maxn]; 13 14 int n, m; 15 16 int dis[maxn], inq[maxn]; 17 void spfa(int s) { 18 queue<int> Q; 19 memset(inq, 0, sizeof(inq)); 20 for (int i = 0; i < n; i++) dis[i] = INF; 21 dis[s] = 0; inq[s] = 1; Q.push(s); 22 while (!Q.empty()) { 23 int u = Q.front(); Q.pop(); 24 inq[u] = false; 25 for (int i = 0; i < G[u].size(); i++) { 26 int v = G[u][i]; 27 if (dis[v] > dis[u] + 1) { 28 dis[v] = dis[u] + 1; 29 if (!inq[v]) { 30 Q.push(v); inq[v] = true; 31 } 32 } 33 } 34 } 35 for (int i = 0; i < n; i++) { 36 mat[s][i] = dis[i]; 37 } 38 } 39 40 int ma_out[maxn][3]; 41 int ma_in[maxn][3]; 42 //处理离i最远的三个顶点,要考虑两种情况,即进入i的点和从i出去的点 43 void pre_ma() { 44 for (int i = 0; i < n; i++) { 45 ma_out[i][0] = ma_out[i][1] =ma_out[i][2]= -1; 46 for (int j = 0; j < n; j++) { 47 if (mat[i][j] >= INF) continue; 48 if (ma_out[i][2]==-1||mat[i][ma_out[i][2]] < mat[i][j]) { 49 ma_out[i][0] = ma_out[i][1]; 50 ma_out[i][1] = ma_out[i][2]; 51 ma_out[i][2] = j; 52 } 53 else if (ma_out[i][1]==-1||mat[i][ma_out[i][1]] < mat[i][j]) { 54 ma_out[i][0] = ma_out[i][1]; 55 ma_out[i][1] = j; 56 } 57 else if (ma_out[i][0]==-1||mat[i][ma_out[i][0]] < mat[i][j]) { 58 ma_out[i][0] = j; 59 } 60 } 61 } 62 for (int i = 0; i < n; i++) { 63 ma_in[i][0] = ma_in[i][1] = ma_in[i][2] = -1; 64 for (int j = 0; j < n; j++) { 65 if (mat[j][i] >= INF) continue; 66 if (ma_in[i][2]==-1||mat[ma_in[i][2]][i] < mat[j][i]) { 67 ma_in[i][0] = ma_in[i][1]; 68 ma_in[i][1] = ma_in[i][2]; 69 ma_in[i][2] = j; 70 } 71 else if (ma_in[i][1]==-1||mat[ma_in[i][1]][i] < mat[j][i]) { 72 ma_in[i][0] = ma_in[i][1]; 73 ma_in[i][1] = j; 74 } 75 else if (ma_in[i][0]==-1||mat[ma_in[i][0]][i] < mat[j][i]) { 76 ma_in[i][0] = j; 77 } 78 } 79 } 80 } 81 82 void init() { 83 for (int i = 0; i < n; i++) G[i].clear(); 84 } 85 86 int main() { 87 while (scanf("%d%d", &n, &m) == 2 && n) { 88 init(); 89 for (int i = 0; i < m; i++) { 90 int u, v; 91 scanf("%d%d", &u, &v); u--, v--; 92 G[u].push_back(v); 93 } 94 for (int i = 0; i < n; i++) spfa(i); 95 pre_ma(); 96 int ans = -1; 97 int nds[4] = { 0 }; 98 //枚举中间两个点,再算旁边两个点 99 for (int i = 0; i < n; i++) { 100 for (int j = 0; j < n; j++) { 101 if (i == j) continue; 102 if (mat[i][j] >= INF) continue; 103 for (int k = 0; k < 3; k++) { 104 for (int l = 0; l < 3; l++) { 105 if (ma_in[i][k] == -1 || ma_out[j][l] == -1) continue; 106 if (ma_in[i][k] == i || ma_in[i][k] == j || ma_in[i][k] == ma_out[j][l]) continue; 107 if (ma_out[j][l] == i || ma_out[j][l] == j) continue; 108 if (ans < mat[ma_in[i][k]][i] + mat[i][j] + mat[j][ma_out[j][l]]) { 109 ans = mat[ma_in[i][k]][i] + mat[i][j] + mat[j][ma_out[j][l]]; 110 nds[0] = ma_in[i][k]; 111 nds[1] = i; 112 nds[2] = j; 113 nds[3] = ma_out[j][l]; 114 } 115 } 116 } 117 } 118 } 119 printf("%d %d %d %d\n", nds[0] + 1, nds[1] + 1, nds[2] + 1, nds[3] + 1); 120 } 121 return 0; 122 }