http://poj.org/problem?id=1236

题意:

给出一个图,至少要选多少个点才能遍历全图和至少需要添加多少边使得整个图是强连通。

 

思路:

强连通计算连通分量后缩点,计算入度为0的点和出度为0的点。

第一个答案就是出度为0的点,第二个就是max(出度,入度)。

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<vector>
 6 #include<stack>
 7 #include<queue>
 8 #include<cmath>
 9 #include<map>
10 using namespace std;
11 
12 const int maxn=100+5;
13 
14 int n;
15 
16 vector<int> G[maxn];
17 int in[maxn],out[maxn];
18 int pre[maxn],lowlink[maxn],sccno[maxn],dfs_clock,scc_cnt;
19 stack<int> S;
20 
21 void dfs(int u)
22 {
23     pre[u]=lowlink[u]=++dfs_clock;
24     S.push(u);
25     for(int i=0;i<G[u].size();i++)
26     {
27         int v=G[u][i];
28         if(!pre[v])
29         {
30             dfs(v);
31             lowlink[u]=min(lowlink[u],lowlink[v]);
32         }
33         else if(!sccno[v])
34         {
35             lowlink[u]=min(lowlink[u],pre[v]);
36         }
37     }
38     if(lowlink[u]==pre[u])
39     {
40         scc_cnt++;
41         for(;;)
42         {
43             int x=S.top(); S.pop();
44             sccno[x]=scc_cnt;
45             if(x==u)  break;
46         }
47     }
48 }
49 
50 void find_scc()
51 {
52     dfs_clock=scc_cnt=0;
53     memset(sccno,0,sizeof(sccno));
54     memset(pre,0,sizeof(pre));
55     for(int i=1;i<=n;i++)
56         if(!pre[i])  dfs(i);
57 }
58 
59 
60 int main()
61 {
62     //freopen("D:\\input.txt","r",stdin);
63     while(~scanf("%d",&n))
64     {
65         for(int i=1;i<=n;i++)  G[i].clear();
66         for(int u=1;u<=n;u++)
67         {
68             while(true)
69             {
70                 int x;
71                 scanf("%d",&x);
72                 if(x==0)  break;
73                 G[u].push_back(x);
74             }
75         }
76         find_scc();
77 
78         for(int i=1;i<=scc_cnt;i++)   in[i]=out[i]=1;
79         for(int u=1;u<=n;u++)
80         {
81             for(int i=0;i<G[u].size();i++)
82             {
83                 int v=G[u][i];
84                 if(sccno[u]!=sccno[v])   in[sccno[v]]=out[sccno[u]]=0;
85             }
86         }
87         int a=0,b=0;
88         for(int i=1;i<=scc_cnt;i++)
89         {
90             if(in[i])  a++;
91             if(out[i]) b++;
92         }
93         int ans=max(a,b);
94         if(scc_cnt==1)  a=1,ans=0;
95         printf("%d\n%d\n",a,ans);
96     }
97     return 0;
98 }