POJ 1236Network of Schools強聯通分量
阿新 • • 發佈:2018-12-12
http://poj.org/problem?id=1236
//看強聯通分量
在有向無環圖中,邊變為了強連通分量之間的檔案傳輸關係。意味這:只要一個強連通分量有入 邊,那麼就可以通過這個入邊從另外一個分量中接收檔案。但是,無環圖意味著肯定存在沒有入 度(入度為0)的強連通分量,這些強連通分量沒有檔案來源,所以要作為投放檔案的位置。那麼, 第一問就只需要計算出縮點後入度為0的強連通分量數目即可。 而第二個問題,把一個有向無環圖轉換為一個強連通分量。強連通分量的主要特徵是:每個點的 入度和出度都不為0,那麼計算出入度為0的點的個數SumIn和出度為0的點的個數SumOut,題 目就變為了:在入度為0的點和出出度為0的點之間最少加多少邊。很明顯的可以看出,答案就是 max(SumIn,SumOut)
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; const int N=105; typedef long long ll; inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } int n; struct edge{ int v,ne; }e[N*N]; int h[N],cnt=0; inline void ins(int u,int v){ cnt++; e[cnt].v=v;e[cnt].ne=h[u];h[u]=cnt; } int dfn[N],low[N],belong[N],dfc,scc; int st[N],top=0; void dfs(int u){ dfn[u]=low[u]=++dfc; st[++top]=u; for(int i=h[u];i;i=e[i].ne){ int v=e[i].v; if(!dfn[v]){ dfs(v); low[u]=min(low[u],low[v]); }else if(!belong[v]) low[u]=min(low[u],dfn[v]); } if(low[u]==dfn[u]){ scc++; while(true){ int x=st[top--]; belong[x]=scc; if(x==u) break; } } } int outd[N],ind[N]; void point(){ for(int u=1;u<=n;u++) for(int i=h[u];i;i=e[i].ne){ int v=e[i].v; if(belong[u]!=belong[v]) outd[belong[u]]++,ind[belong[v]]++; } } int main(){ n=read(); for(int u=1;u<=n;u++){ int v=read(); while(v!=0){ins(u,v);v=read();} } for(int i=1;i<=n;i++) if(!dfn[i]) dfs(i); point(); int cnt1=0,cnt2=0; for(int i=1;i<=scc;i++){ if(ind[i]==0) cnt1++; if(outd[i]==0) cnt2++; } if(scc==1) printf("1\n0"); else printf("%d\n%d",cnt1,max(cnt1,cnt2)); }
#include<cstdio> #include<cstring> #include<vector> #include<stack> #include<algorithm> using namespace std; const int maxn=100+10; int n,m; vector<int> G[maxn]; stack<int> S; int dfs_clock, scc_cnt; int pre[maxn],low[maxn],sccno[maxn]; int in0[maxn],out0[maxn]; void dfs(int u) { pre[u]=low[u]=++dfs_clock; S.push(u); for(int i=0; i<G[u].size(); i++) { int v=G[u][i]; if(!pre[v]) { dfs(v); low[u]=min(low[u],low[v]); } else if(!sccno[v]) low[u]=min(low[u],pre[v]); } if(low[u]==pre[u]) { scc_cnt++; while(true) { int x=S.top(); S.pop(); sccno[x]=scc_cnt; if(x==u) break; } } } void find_scc(int n) { dfs_clock=scc_cnt=0; memset(pre,0,sizeof(pre)); memset(sccno,0,sizeof(sccno)); for(int i=0;i<n;i++) if(!pre[i]) dfs(i); } int main() { while(scanf("%d",&n)==1&&n) { for(int i=0;i<n;i++) G[i].clear(); for(int u=0;u<n;u++) { int v; while(scanf("%d",&v)==1&&v) { v--; G[u].push_back(v); } }//從0開始編號; find_scc(n);//進行演算法,求強連通分量; for(int i=1;i<=scc_cnt;i++) in0[i]=out0[i]=true;//目前初始化為true; for(int u=0;u<n;u++) for(int i=0;i<G[u].size();i++) { int v=G[u][i]; if(sccno[u]!=sccno[v]) in0[sccno[v]]=out0[sccno[u]]=false; //如果不屬於一個強連通分量;a->b //剩餘為true的就是強連通分量所在點; //兩個聯通分量包含元素個數不同,不為一個強連通分量; } int a=0, b=0; for(int i=1;i<=scc_cnt;i++) { if(in0[i]) a++;//入度為0為強連通分量個數; if(out0[i]) b++;//出度為0 } if(scc_cnt==1) printf("1\n0\n");//只有一個強連通分量; else printf("%d\n%d\n",a,max(a,b));// } return 0; }