poj 1236(强连通分量)

题目大意:   给定一个n (n<=100)个点的有向图,

问:Q1、最少需要选择多少个点,使得从这些点出发能遍历完整个图; 

  Q2、最少需要添加多少条有向边,使得整个图成为强连通图; 

  分析: 

    求出强连通分量后进行缩点,得到每个强连通分量的入度in[],出度out[]; 

  Q1: 入度为0的强连通分量个数;   Q2: max( 入度为0的强连通分量个数 , 出度为0的强连通分量个数  );

  注意的地方:假如原图就是一个强连通图。则显然Q2是0.

kosaraju:

View Code
  1 // File Name: 1236.cpp
  2 // Author: Missa
  3 // Created Time: 2013/2/6 星期三 19:44:12
  4 
  5 #include<iostream>
  6 #include<cstdio>
  7 #include<cstring>
  8 #include<algorithm>
  9 #include<cmath>
 10 #include<queue>
 11 #include<stack>
 12 #include<string>
 13 #include<vector>
 14 #include<cstdlib>
 15 #include<map>
 16 using namespace std;
 17 
 18 const int maxn = 1e2+5;
 19 int n;
 20 vector<int>adj[maxn];
 21 vector<int>radj[maxn];
 22 vector<int>ord;
 23 bool vis[maxn];
 24 int ma[maxn];
 25 int cnt;
 26 void init()
 27 {
 28     for(int i=0;i<maxn;i++)
 29     {
 30         adj[i].clear();
 31         radj[i].clear();
 32     }
 33     ord.clear();
 34     cnt=0;
 35 }
 36 void dfs1(int v)
 37 {
 38     vis[v]=1;
 39     for(int i=0;i<adj[v].size();i++)
 40         if(!vis[adj[v][i]])
 41             dfs1(adj[v][i]);
 42     ord.push_back(v);
 43 }
 44 void dfs2(int v)
 45 {
 46     vis[v]=1;
 47     ma[v]=cnt;
 48     for(int i=0;i<radj[v].size();i++)
 49         if(!vis[radj[v][i]])
 50             dfs2(radj[v][i]);
 51 }
 52 void kosaraju()
 53 {
 54     memset(vis,0,sizeof(vis));
 55     ord.clear();
 56     for(int i=1;i<=n;i++)
 57         if(!vis[i])
 58             dfs1(i);
 59     memset(vis,0,sizeof(vis));
 60     cnt=0;
 61     for(int i=ord.size()-1;i>=0;i--)
 62     {
 63         if(!vis[ord[i]])
 64         {
 65             cnt++;
 66             dfs2(ord[i]);
 67         }
 68     }
 69 }
 70 void read()
 71 {
 72     for(int i=1;i<=n;i++)
 73     {
 74         int x;
 75         while(scanf("%d",&x))
 76         {
 77             if(x==0) break;
 78             adj[i].push_back(x);
 79             radj[x].push_back(i);
 80         }
 81     }
 82 }
 83 void solve()
 84 {
 85     int ans1=0,ans2=0;
 86     int in[maxn],out[maxn];//入度,出度
 87     memset(in,0,sizeof(in));
 88     memset(out,0,sizeof(out));
 89     for(int i=1;i<=n;i++)
 90     {
 91         for(int j=0;j<adj[i].size();j++)
 92         {
 93             int tt=adj[i][j];
 94             if(ma[i]==ma[tt]) continue;
 95             out[ma[i]]++;
 96             in[ma[tt]]++;
 97         }
 98     }
 99     for(int i=1;i<=cnt;i++)
100     {
101         if(in[i]==0) ans1++;
102         if(out[i]==0) ans2++;
103     }
104     printf("%d\n",ans1);
105     if(cnt==1)//原图是一个强连通分量
106         printf("0\n");
107     else
108         printf("%d\n",max(ans1,ans2));
109 }
110 int main()
111 {
112     while(~scanf("%d",&n))
113     {
114         init();
115         read();
116         kosaraju();
117         solve();
118     }
119     return 0;
120 }

 

转载于:https://www.cnblogs.com/Missa/archive/2013/02/06/2908139.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值