POJ1236:Network of Schools (思維+Tarjan縮點)
Network of Schools
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 24880 | Accepted: 9900 |
題目鏈接:http://poj.org/problem?id=1236
Description:
A number of schools are connected to a computer network. Agreements have been developed among those schools: each school maintains a list of schools to which it distributes software (the “receiving schools”). Note that if B is in the distribution list of school A, then A does not necessarily appear in the list of school B
Input:
The first line contains an integer N: the number of schools in the network (2 <= N <= 100). The schools are identified by the first N positive integers. Each of the next N lines describes a list of receivers. The line i+1 contains the identifiers of the receivers of school i. Each list ends with a 0. An empty list contains a 0 alone in the line.
Output:
Your program should write two lines to the standard output. The first line should contain one positive integer: the solution of subtask A. The second line should contain the solution of subtask B.
Sample Input:
5 2 4 3 0 4 5 0 0 0 1 0
Sample Output:
1 2
題意:
給出一個有向圖,然後要你輸出兩個任務的答案:
1.至少需要從多少個點出發,能夠到達所有的點;2.最少需要連多少條邊,能夠使得從任意點出發都能夠到達其它所有點。
題解:
這個題我一開始想的就是直接暴力,但很明顯第二個問題行不通,所以就要考慮一些性質,或者用一些數學思想。
第一個問題還是比較好想,入度為0的點的個數即位答案,如果不存在入度為0的點,答案就是1。簡略證明如下(題目保證圖是連通的):
假設入度為0的點為n,那麽至少需要n個點才能遍及所有點,然後對於其余入度非0的點來說,必然是由其他點到達的,如果這個點不在環上,那麽就必定是從一個入度為0的點來的;如果這個點在環上,這個環中的所有點也會由其余入度為0的點到達;假設這是個單獨的環,那麽答案為1。
第二個問題要求所有點都互相可以到達。那麽我們可以知道的是,圖中必然不會存在入度為0以及出度為0的點,假設這兩者的個數分別為n,m。
那麽最優的連邊方法就是入度為0的點與出度為0的點匹配,最後剩下的亂連就行了,所以最後答案就是max(n,m)。證明的話yy一下吧。
因為我們剛才是基於有向無環圖來思考的,環的存在應該把它當作一個點,所以考慮Tarjan縮波點就行了。
代碼如下:
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <queue> #include <stack> using namespace std; typedef long long ll; const int N = 105; int n,tot; int head[N],in[N],out[N],low[N],dfn[N],vis[N],scc[N]; struct Edge{ int u,v,next; }e[N*N<<1],edge[N*N<<1]; void adde(int u,int v){ e[tot].u=u;e[tot].v=v;e[tot].next=head[u];head[u]=tot++; } stack <int> s; int T,num; void Tarjan(int u){ dfn[u]=low[u]=++T;vis[u]=1; s.push(u); for(int i=head[u];i!=-1;i=e[i].next){ int v=e[i].v; if(!vis[v]){ Tarjan(v); low[u]=min(low[u],low[v]); }else if(!scc[v]){ low[u]=min(low[u],dfn[v]); } } if(low[u]==dfn[u]){ num++;int now; do{ now = s.top();s.pop(); scc[now]=num; }while(!s.empty() && now!=u); } } int main(){ scanf("%d",&n); int m=0; memset(head,-1,sizeof(head)); for(int i=1;i<=n;i++){ int v; while(scanf("%d",&v)!=EOF){ if(v==0) break ; edge[++m].u=i;edge[m].v=v; adde(i,v); } } //cout<<m<<endl; for(int i=1;i<=n;i++){ if(!vis[i]) Tarjan(i); } for(int i=1;i<=m;i++){ int u=edge[i].u,v=edge[i].v; if(scc[u]!=scc[v]){ in[scc[v]]++;out[scc[u]]++; } } int cnt1=0,cnt2=0; for(int i=1;i<=num;i++){ if(!in[i]) cnt1++; if(!out[i]) cnt2++; } //cout<<num<<endl; if(num==1) cout<<1<<endl<<0; else cout<<cnt1<<endl<<max(cnt2,cnt1); return 0; }
POJ1236:Network of Schools (思維+Tarjan縮點)