zoukankan      html  css  js  c++  java
  • hdu 1269+hdu 2767(强连通分量)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1269

    View Code
     1 #include<iostream>
     2 #include<vector>
     3 #include<stack>
     4 const int MAXN=10000+10;
     5 using namespace std;
     6 vector<int>mp[MAXN];
     7 stack<int>S;
     8 int n,m;
     9 int _count;
    10 int cnt;
    11 bool mark[MAXN];
    12 int dfn[MAXN];
    13 int low[MAXN];
    14 
    15 //求强连通分量tarjan
    16 void Tarjan(int u){
    17     dfn[u]=low[u]=++cnt;
    18     mark[u]=true;
    19     S.push(u);
    20     for(int i=0;i<mp[u].size();i++){
    21         int v=mp[u][i];
    22         if(dfn[v]==0){
    23             Tarjan(v);
    24             low[u]=min(low[u],low[v]);
    25         }else if(mark[v]&&dfn[v]<low[u]){
    26             low[u]=dfn[v];
    27         }
    28     }
    29     if(low[u]==dfn[u]){
    30         _count++;
    31         int v;
    32         do{
    33             v=S.top();
    34             S.pop();
    35             mark[v]=false;
    36         }while(u!=v);
    37     }
    38 }
    39 
    40         
    41 int main(){
    42     while(~scanf("%d%d",&n,&m)){
    43         if(n==0&&m==0)break;
    44         for(int i=1;i<=n;i++)mp[i].clear();
    45         for(int i=1;i<=m;i++){
    46             int x,y;
    47             scanf("%d%d",&x,&y);
    48             mp[x].push_back(y);
    49         }
    50         memset(mark,false,sizeof(mark));
    51         memset(dfn,0,sizeof(dfn));
    52         memset(low,0,sizeof(low));
    53         _count=0;
    54         cnt=0;
    55         for(int i=1;i<=n;i++){
    56             if(dfn[i]==0){
    57                 Tarjan(i);
    58             }
    59         }
    60         if(_count>1){
    61             printf("No\n");
    62         }else
    63             printf("Yes\n");
    64     }
    65     return 0;
    66 }

     题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2767

    思路:可以用tarjan算法求出求出有向图的强连通分量,并进行染色,然后在缩点,缩点的好处就是把原本杂乱的有向图变成有向无环图。。。

    然后统计入度为0的点和出度为0的点,取其较大值就是所求的要求添加的最少的边的条数了。

    View Code
     1 #include<iostream>
     2 #include<vector>
     3 #include<stack>
     4 const int MAXN=20000+10;
     5 using namespace std;
     6 vector<int>mp[MAXN];
     7 stack<int>S;
     8 bool mark[MAXN];
     9 int dfn[MAXN],low[MAXN];
    10 int color[MAXN];//染色
    11 int n,m,_count,cnt;
    12 int from[MAXN],to[MAXN];
    13 
    14 
    15 //求有向图强连通分量
    16 void Tarjan(int u){
    17     dfn[u]=low[u]=++cnt;
    18     mark[u]=true;
    19     S.push(u);
    20     for(int i=0;i<mp[u].size();i++){
    21         int v=mp[u][i];
    22         if(dfn[v]==0){
    23             Tarjan(v);
    24             low[u]=min(low[u],low[v]);
    25         }else if(mark[v]&&dfn[v]<low[u]){
    26             low[u]=dfn[v];
    27         }
    28     }
    29     if(low[u]==dfn[u]){
    30         _count++;
    31         int v;
    32         do{
    33             v=S.top();
    34             S.pop();
    35             mark[v]=false;//相当于出栈
    36             color[v]=_count;  //缩点,把一个杂乱无章的有向图变成一个有向无环图
    37         }while(u!=v);
    38     }
    39 }
    40 
    41 int main(){
    42     int _case;
    43     scanf("%d",&_case);
    44     while(_case--){
    45         scanf("%d%d",&n,&m);
    46         for(int i=1;i<=n;i++)mp[i].clear();
    47         for(int i=1;i<=m;i++){
    48             int x,y;
    49             scanf("%d%d",&x,&y);
    50             mp[x].push_back(y);
    51         }
    52         memset(mark,false,sizeof(mark));
    53         memset(dfn,0,sizeof(dfn));
    54         memset(low,0,sizeof(low));
    55         memset(color,0,sizeof(color));
    56         memset(from,0,sizeof(from));
    57         memset(to,0,sizeof(to));
    58         _count=0,cnt=0;
    59         for(int i=1;i<=n;i++){
    60             if(dfn[i]==0){
    61                 Tarjan(i);
    62             }
    63         }
    64         if(_count==1){
    65             printf("0\n");
    66             continue;
    67         }
    68         for(int i=1;i<=n;i++){
    69             for(int j=0;j<mp[i].size();j++){
    70                 int k=mp[i][j];
    71                 if(color[i]!=color[k]){
    72                     from[color[i]]++;//标记color[]表示记录的是第几个连通分量
    73                     to[color[k]]++;
    74                 }
    75             }
    76         }
    77         int in=0,out=0;
    78         for(int i=1;i<=_count;i++){
    79             if(from[i]==0)out++;//出度为0
    80             if(to[i]==0)in++;//入度为0
    81         }
    82         printf("%d\n",max(in,out));//max(in,out)即为最少需要连的边
    83     }
    84     return 0;
    85 }
    86 
    87 
    88                 
    89         
    90 
    91 
    92                 
    93             

    下面贴一个tarjan的算法流程:

    tarjan(u)

    {

      dfn[u]=low[u]=++cnt;

      Stack.push(u)

      for(each(u,v) in E)

        if(v is not visited)

          tarjan(v);

          low[u]=min(low[u],low[v]);

        else if(v is in Stack)

          low[u]=min(low[u],dfn[v]);

      if(dfn[u]==low[u])

        repeat

          v=Stack.pop

          print v

        until(u==v);

    }

  • 相关阅读:
    进制转换问题
    奶牛野炊
    BFS
    深搜DFS
    Map容器之热血格斗场
    衣服尺码
    BZOJ2789 [Poi2012]Letters
    BZOJ1098 [POI2007]办公楼biu
    BZOJ1753 [Usaco2005 qua]Who's in the Middle
    BZOJ2442 [Usaco2011 Open]修剪草坪
  • 原文地址:https://www.cnblogs.com/wally/p/3010712.html
Copyright © 2011-2022 走看看