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);

}

你可能感兴趣的:(HDU)