• 150904 高速公路 ccf


    参考

    Kosaraju

    https://www.cnblogs.com/nullzx/p/6437926.html

    tarjan

    https://blog.csdn.net/qq_34374664/article/details/77488976

    思路

    求回路也就是求图的强连通分量

    共有两种算法:Kosaraju与tarjan,其中Kosaraju算法较易理解但需要两次dfs,tarjan算法较难理解但只需dfs一次。

    两种算法的详解见参考。

    概述:

    Kosaraju

    1、对图的反向图进行一次逆后序dfs遍历

    2、按照逆后序遍历得到的栈中点的出栈顺序对原图进行dfs遍历,每一次遍历访问到的点就属于一个强连通分量。

    tarjan

     1 /*
     2 dfn为访问序号(时间戳)
     3 low为当前节点及其子树中结点最小的访问序号,类似并查集
     4 */
     5 void tarjan(int u){
     6 
     7   DFN[u]=Low[u]=++Index // 为节点u设定次序编号和Low初值
     8 
     9   Stack.push(u)   // 将节点u压入栈中
    10 
    11   for each (u, v) in E // 枚举每一条边
    12     {
    13             if (v is not visted) // 如果节点v未被访问过
    14 
    15     {
    16                 tarjan(v) // 继续向下找
    17                 Low[u] = min(Low[u], Low[v])
    18             }    
    19 
    20     else if (v in S) // 如果节点u还在栈内
    21 
    22     {   Low[u] = min(Low[u], DFN[v])   }
    23     }
    24 
    25   if (DFN[u] == Low[u]) // 如果节点u是强连通分量的根
    26    {
    27            repeat 
    28        
    29            v = S.pop  // 将v退栈,为该强连通分量中一个顶点
    30 
    31        print v
    32 
    33        until (u== v)    
    34    }
    35 
    36 }                    
    tarjan伪代码

    实现

    Kosaraju

     1 //Kosaraju
     2 #include<bits/stdc++.h>
     3 
     4 using namespace std;
     5 
     6 #define MAXN 10005
     7 
     8 vector<int> Map1[MAXN];
     9 vector<int> Map2[MAXN];
    10 stack<int> sta; 
    11 int vis[MAXN];
    12 long long int ans=0,num=0;
    13 int n,m;
    14 
    15 int size,v;
    16 void dfs2(int s){
    17     
    18     for(int i=0;i<Map2[s].size();i++){
    19         v=Map2[s][i];
    20         if(vis[v]==0){
    21             vis[v]=1;
    22             dfs2(v);    
    23         }
    24     }
    25     sta.push(s);
    26 }
    27 
    28 void dfs1(int s){
    29     for(int i=0;i<Map1[s].size();i++){
    30         v=Map1[s][i];
    31         if(vis[v]==0){
    32             //cout<<v<<' ';
    33             vis[v]=1;
    34             num++;
    35             dfs1(v);
    36         }
    37     }
    38 }
    39 
    40 long long int C(int x){
    41     if(x<=1){
    42         return 0;
    43     }
    44     else{
    45         long long int a=1;
    46         for(int i=x;i>x-2;i--){
    47             a*=i;
    48         }
    49         return a/2;
    50     }
    51 }
    52 
    53 int main(){
    54     cin>>n>>m;
    55     int a,b;
    56     for(int i=0;i<m;i++){
    57         cin>>a>>b;
    58         Map1[a].push_back(b);
    59         Map2[b].push_back(a);
    60     }
    61     
    62     memset(vis,0,sizeof(vis));
    63     for(int i=0;i<=n;i++){
    64         if(vis[i]==0){
    65             vis[i]=1;
    66             dfs2(i);
    67         }
    68     }
    69     
    70     memset(vis,0,sizeof(vis));
    71     int v;
    72     while(!sta.empty()){
    73         v=sta.top();
    74         sta.pop();
    75         
    76         if(vis[v]==0){
    77             //cout<<v<<' ';
    78             vis[v]=1;
    79             num=1;
    80             dfs1(v);
    81             //cout<<num<<endl;
    82             ans+=C(num);
    83         }
    84     }
    85 
    86     cout<<ans;
    87     
    88     return 0;
    89 }
    View Code

    tarjan

     1 //tarjan
     2 
     3 #include<bits/stdc++.h>
     4 
     5 using namespace std;
     6 
     7 #define MAXN 10005
     8 
     9 vector<int> Map[MAXN];
    10 stack<int> sta;
    11 int vis[MAXN];
    12 int dfn[MAXN];
    13 int low[MAXN];
    14 int insta[MAXN];
    15 long long int num=0,ans=0;
    16 int n,m,index;
    17 
    18 long long int C(int x){
    19     if(x<=1){
    20         return 0;
    21     }
    22     else{
    23         long long int a=1;
    24         for(int i=x;i>x-2;i--){
    25             a*=i;
    26         }
    27         return a/2;
    28     }
    29 }
    30 
    31 void tarjan(int u)
    32 {
    33     index++;
    34     dfn[u]=low[u]=index;
    35     vis[u]=1;
    36     sta.push(u);
    37     insta[u]=1;
    38     int  size=Map[u].size();
    39     for(int i=0;i<size;i++){
    40         int v=Map[u][i];
    41         if(vis[v]==0){
    42             tarjan(v);
    43             low[u]=min(low[u],low[v]);
    44         }
    45         else if(insta[v]==1){
    46             low[u]=min(low[u],dfn[v]);
    47         }
    48     }
    49     num=0;
    50     if(dfn[u]==low[u]){
    51         int v;
    52         do{
    53             v=sta.top();
    54             //cout<<v<<' ';
    55             sta.pop();
    56             insta[v]=0;
    57             num++;
    58         }while(v!=u);
    59         //cout<<endl;
    60     }
    61     ans+=C(num);
    62 }
    63 
    64 int main(){
    65     cin>>n>>m;
    66     int a,b;
    67     for(int i=0;i<m;i++){
    68         cin>>a>>b;
    69         Map[a].push_back(b);
    70     }
    71     memset(vis,0,sizeof(vis));
    72     memset(insta,0,sizeof(insta));
    73     index=0;
    74     for(int i=1;i<=n;i++){
    75         if(vis[i]==0){            
    76             tarjan(i);
    77         }
    78     }
    79     cout<<ans;
    80     
    81     return 0;
    82 }
    View Code

    题目

    问题描述
     
      某国有n个城市,为了使得城市间的交通更便利,该国国王打算在城市之间修一些高速公路,由于经费限制,国王打算第一阶段先在部分城市之间修一些单向的高速公路。
      现在,大臣们帮国王拟了一个修高速公路的计划。看了计划后,国王发现,有些城市之间可以通过高速公路直接(不经过其他城市)或间接(经过一个或多个其他城市)到达,而有的却不能。如果城市A可以通过高速公路到达城市B,而且城市B也可以通过高速公路到达城市A,则这两个城市被称为便利城市对。
      国王想知道,在大臣们给他的计划中,有多少个便利城市对。
     
    输入格式
     
      输入的第一行包含两个整数nm,分别表示城市和单向高速公路的数量。
      接下来m行,每行两个整数ab,表示城市a有一条单向的高速公路连向城市b
     
    输出格式
     
      输出一行,包含一个整数,表示便利城市对的数量。
     
    样例输入
     
    5 5
    1 2
    2 3
    3 4
    4 2
    3 5
     
    样例输出
     
    3
     
    样例说明

      城市间的连接如图所示。有3个便利城市对,它们分别是(2, 3), (2, 4), (3, 4),请注意(2, 3)和(3, 2)看成同一个便利城市对。
     
    评测用例规模与约定
     
      前30%的评测用例满足1 ≤ n ≤ 100, 1 ≤ m ≤ 1000;
      前60%的评测用例满足1 ≤ n ≤ 1000, 1 ≤ m ≤ 10000;
      所有评测用例满足1 ≤ n ≤ 10000, 1 ≤ m ≤ 100000。
     
  • 相关阅读:
    UVA
    codevs3196 黄金宝藏
    UVA
    UVA
    3424:Candies(差分约束,Dijkstra)(配对堆优化
    1062:昂贵的聘礼(最短路/枚举)
    01分数规划问题(二分法与Dinkelbach算法)
    Desert King(01分数规划问题)(最优斜率生成树)
    Enlarge GCD(素数筛)
    hdu2085-2086
  • 原文地址:https://www.cnblogs.com/Gru-blog/p/11321602.html
Copyright © 2020-2023  润新知