• 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
    ", nds[0] + 1, nds[1] + 1, nds[2] + 1, nds[3] + 1);
    120     }
    121     return 0;
    122 }
  • 相关阅读:
    人人都有数字替身的时代马上到来
    教你如何在linux下查看服务是否已经启动或者关闭
    提前了解2019年物联网发展的六大趋势
    本科理工男如何学习Linux
    linux常见命令ps的应用
    useradd 命令的常见用法
    简单聊聊Linux学习经历
    什么是公网IP、内网IP和NAT转换?
    远程获得的有趣的linux命令
    js练习题之查找数组中的位子
  • 原文地址:https://www.cnblogs.com/fenice/p/5518438.html
Copyright © 2020-2023  润新知