1. 程式人生 > >POJ 1236 Network of Schools(tarjan求強連通分量+思維)

POJ 1236 Network of Schools(tarjan求強連通分量+思維)

一個 div http mes pos 全部 tde bre 一點

題目鏈接:http://poj.org/problem?id=1236

題目大意:

給你一個網絡(有向圖),有兩個任務:
①求出至少同時需要幾份副本可以使得整個網絡都獲得副本
②至少添加多少信息表(有向邊)使得副本傳到任一點,都可以使得整個網絡都獲得副本

解題思路:

即給定一個有向圖,求:

①至少要選幾個頂點,才能做到從這些頂點出發,可以到達全部頂點

②至少要加多少條邊,才能使得從任何一個頂點出發,都能到達全部頂點
縮點後,分別求出出度入度為0的點數為sum1,sum2,
問題①的答案就為sum2;
問題②的答案為max(sum1,sum2)(即使得所有點的出度入度都大於0)。
註意,只有一個點時,不需要添加邊,答案為1,0。

代碼

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<stack>
 6 #include<vector>
 7 using namespace std;
 8 const int N=105;
 9 
10 int n,cnt,num;                            //cnt為當前dfs序,num為縮點編號
11 int low[N],dfn[N],fa[N],indeg[N],outdeg[N];//
dfn為dfs序,low為節點能夠通過返回的最早的祖先(註意這裏跟求割邊割點裏的low不同) 12 vector<int>v[N]; //fa為節點所屬的強聯通分量的編號.indeg和outdeg為縮點的入度、出度 13 stack<int>sk; 14 15 void init(){ 16 cnt=num=0; 17 for(int i=1;i<=n;i++){ 18 v[i].clear(); 19 } 20 memset(fa,0,sizeof(fa));
21 memset(low,0,sizeof(low)); 22 memset(dfn,0,sizeof(dfn)); 23 memset(indeg,0,sizeof(indeg)); 24 memset(outdeg,0,sizeof(outdeg)); 25 } 26 27 //求強聯通分量 28 void tarjan(int u){ 29 low[u]=dfn[u]=++cnt; 30 sk.push(u); 31 for(int i=0;i<v[u].size();i++){ 32 int t=v[u][i]; 33 if(!dfn[t]){ //未被訪問 34 tarjan(t); 35 low[u]=min(low[u],low[t]); 36 } 37 else if(!fa[t]) low[u]=min(low[u],dfn[t]); //被訪問過且在棧中 38 } 39 if(low[u]==dfn[u]){ 40 num++; 41 while(!sk.empty()){ 42 int t=sk.top(); 43 sk.pop(); 44 fa[t]=num; 45 if(t==u) break; 46 } 47 } 48 } 49 50 int main(){ 51 while(~scanf("%d",&n)){ 52 init(); 53 for(int i=1;i<=n;i++){ 54 int x; 55 while(~scanf("%d",&x)&&x) v[i].push_back(x); 56 } 57 for(int i=1;i<=n;i++){ //遍歷所有點 58 if(!dfn[i]) tarjan(i); 59 } 60 for(int i=1;i<=n;i++){ //縮點,並求出相應的出度入度是否為0(註意不是求出入度) 61 for(int j=0;j<v[i].size();j++){ 62 int t=v[i][j]; 63 if(fa[t]!=fa[i]){ 64 outdeg[fa[i]]=1; 65 indeg[fa[t]]=1; 66 } 67 } 68 } 69 int sum1=0,sum2=0; 70 for(int i=1;i<=num;i++){ 71 if(outdeg[i]==0) 72 sum1++; 73 if(indeg[i]==0) 74 sum2++; 75 } 76 if(num==1) //只有一個點時要特判 77 puts("1\n0"); 78 else printf("%d\n%d\n",sum2,max(sum1,sum2)); 79 } 80 return 0; 81 }

POJ 1236 Network of Schools(tarjan求強連通分量+思維)