zoukankan      html  css  js  c++  java
  • POJ3114 Countries in War (强连通分量 + 缩点 + 最短路径 + 好题)

    题目链接

    题意是说在几个邮局之间传送一份信件,如果出发点和终止点在同一个国家传递,则时间为0,否则让你求花费最少时间,如果不能传到,则输出Nao e possivel entregar a carta。判断邮局是否在同一个国家的依据是发出的信件可以相互到达。
    如果直接求最短路则无法判断两个邮局是否在同一个国家,判断两个邮局是否属于同一个国家的标志是在这个国家邮局间可以相互到达,那么这就是强连通了,所以要先缩点判读邮局是否在同一个国家,如果不是,则重新建图,建图的时候要维护好边权,求出最短边权,在用dijkstra求出最短路即可。
      1 #include <iostream>
      2 #include <cstring>
      3 #include <cstdio>
      4 #include <algorithm>
      5 #include <vector>
      6 using namespace std;
      7 const int Max = 505;
      8 const int INF = 0x3f3f3f3f;
      9 int n, m, dfs_clock, scc_cnt, scnt;
     10 int g[Max][Max], pre[Max], low[Max], Stack[Max], sccno[Max];
     11 int G[Max][Max];
     12 int head[Max], num;
     13 struct Edge
     14 {
     15     int v, Next;
     16 };
     17 Edge edge[Max * Max];
     18 void addEdge(int u, int v)
     19 {
     20     edge[num].v = v;
     21     edge[num].Next = head[u];
     22     head[u] = num++;
     23 }
     24 void init()
     25 {
     26     memset(head, -1, sizeof(head));
     27     memset(pre, 0, sizeof(pre));
     28     //memset(low, 0, sizeof(low));
     29     memset(sccno, 0, sizeof(sccno));
     30     scnt = dfs_clock = scc_cnt = num = 0;
     31     for (int i = 1; i <= n; i++)
     32         for (int j = i; j <= n; j++)
     33         {
     34             if (i == j)
     35                 G[i][j] = g[i][j] = 0;
     36             else
     37             {
     38                 g[i][j] = g[j][i] = INF;
     39                 G[i][j] = G[j][i] = INF;
     40             }
     41         }
     42 }
     43 void dfs(int u)
     44 {
     45     pre[u] = low[u] = ++dfs_clock;
     46     Stack[scnt++] = u;
     47     for (int i = head[u]; i != -1; i = edge[i].Next)
     48     {
     49         int v = edge[i].v;
     50         if (!pre[v])
     51         {
     52             dfs(v);
     53             low[u] = min(low[u], low[v]);
     54         }
     55         else if (!sccno[v])
     56             low[u] = min(low[u], pre[v]);
     57     }
     58     if (low[u] == pre[u])
     59     {
     60         scc_cnt++;
     61         for (; ;)
     62         {
     63             int x = Stack[--scnt];
     64             sccno[x] = scc_cnt;
     65             if ( x == u)
     66                 break;
     67         }
     68     }
     69 }
     70 void find_scc()
     71 {
     72     for (int i = 1; i <= n; i++)
     73     {
     74         if (!pre[i])
     75             dfs(i);
     76     }
     77 }
     78 void build_new_graphic()
     79 {
     80     for (int i = 1; i <= n; i++)
     81     {
     82         for (int j = 1; j <= n; j++)
     83         {
     84             if (i != j && sccno[i] != sccno[j] && g[i][j] != INF) // 不同的连通分量号建立一条有向边。
     85             {
     86                 G[ sccno[i] ][ sccno[j] ] = min(g[i][j], G[ sccno[i] ][ sccno[j] ]);
     87             }
     88         }
     89     }
     90 }
     91 int dist[Max], vis[Max];
     92 void dijkstra(int start, int goal)
     93 {
     94    //利用起点start,终点goal来搞,以前做惯了,直接用起点是1来做了
     95     for (int i = 1; i <= scc_cnt; i++)
     96         dist[i] = G[start][i]; 
     97     memset(vis, 0, sizeof(vis));
     98     dist[start] = 0;
     99     vis[start] = 1;
    100     for (int i = 2; i <= scc_cnt; i++)
    101     {
    102         int minn = INF, pos = 1; // 这里初始化pos为1,否则当下面的循环不满足条件是,执行vis[pos]会出错
    103         for (int j = 1; j <= scc_cnt; j++)
    104         {
    105             if (!vis[j] && minn > dist[j])
    106             {
    107                 minn = dist[j];
    108                 pos = j;
    109             }
    110         }
    111         vis[pos] = 1;
    112         for (int j = 1; j <= scc_cnt; j++)
    113         {
    114             if (!vis[j] && dist[j] > dist[pos] + G[pos][j])
    115                 dist[j] = dist[pos] + G[pos][j];
    116         }
    117     }
    118     if (dist[goal] != INF)
    119         printf("%d
    ", dist[goal]);
    120     else
    121         printf("Nao e possivel entregar a carta
    ");
    122 }
    123 int main()
    124 {
    125     while (scanf("%d%d", &n, &m) != EOF)
    126     {
    127         if (n == 0 && m == 0)
    128             break;
    129         init();
    130         int u, v, c;
    131         for (int i = 1; i <= m; i++)
    132         {
    133             scanf("%d%d%d", &u, &v, &c);
    134             if (g[u][v] > c)
    135             {
    136                 g[u][v] = c;  // 判断重边
    137             }
    138             addEdge(u, v);
    139         }
    140         find_scc();  // 找强连通分量
    141         //cout << scc_cnt << endl;
    142         build_new_graphic();  // 重新构图
    143 
    144         int k;
    145         scanf("%d", &k);
    146         while (k--)
    147         {
    148             scanf("%d%d", &u, &v);
    149             if (sccno[u] == sccno[v])  // 同一连通分量直接输出
    150                 printf("0
    ");
    151             else
    152             {
    153                 dijkstra(sccno[u], sccno[v]);
    154             }
    155         }
    156         printf("
    ");
    157     }
    158 
    159     return 0;
    160 }
    View Code
  • 相关阅读:
    搜房二手频道调研
    智能评论排序
    国外社交网站调研(13年9月)
    百度金融产品的几点看法
    Microvideos for Website/ products
    C#后端代码访问webapi
    基于FineUI-FineUIMVC基础版开发的通用后台框架
    EasyUI, Dialog 在框架页(ifrmae)的Top页面弹出时,拖拽Dialog边缘(以改变窗口大小),UI界面被卡死的解决办法
    在Windows上使用Docker 创建MongoDB 副本集的极简方法(翻译)
    初探ABP--记一些常见的开发问题
  • 原文地址:https://www.cnblogs.com/zhaopAC/p/5351773.html
Copyright © 2011-2022 走看看