IOI 1996 網路協議
阿新 • • 發佈:2018-11-02
一些學校連線在一個計算機網路上。學校之間存在軟體支援協議。每個學校都有它應支援的學校名單(學校 aaa 支援學校 bbb,並不表示學校 bbb 一定支援學校 aaa)。當某校獲得一個新軟體時,無論是直接得到還是網路得到,該校都應立即將這個軟體通過網路傳送給它應支援的學校。因此,一個新軟體若想讓所有連線在網路上的學校都能使用,只需將其提供給一些學校即可。
任務
- 請編一個程式,根據學校間支援協議(各個學校的支援名單),計算最少需要將一個新軟體直接提供給多少個學校,才能使軟體通過網路被傳送到所有學校;
- 如果允許在原有支援協議上新增新的支援關係。則總可以形成一個新的協議,使得此時只需將一個新軟體提供給任何一個學校,其他所有學校就都可以通過網路獲得該軟體。程式設計計算最少需要新增幾條新的支援關係。
首先很顯然的是在一個強連通分量中肯定滿足以上性質
所以我們先進行Tarjan的縮點操作
然後連邊,對於入度為零的點,我們必定需要告訴其中的一個人
然後第一問就解決了(連邊過程中記錄入度)
然後是第二問,因為是任何一個學校,所以我們要求從每個學校可以到另一個學校,也就是從每一個出度為零的的地方加一條入邊
每一個入度為零的地方加一條出邊
一位在這其中出邊和入邊可以一一對應,所以只需要去這兩個值當中較大的一個即可
特別注意,如果只有一個點,那麼Juin不需要連邊,在輸出時要加入特判
下面給出程式碼:
#include<iostream> #include<algorithm> #include<cmath> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> using namespace std; inline int rd(){ int x=0,f=1; char ch=getchar(); for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1; for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0'; return x*f; } inline void write(int x){ if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10+'0'); return ; } int n; int head[1000006],nxt[1000006],to[1000006]; int total=0; void add(int x,int y){ total++; to[total]=y; nxt[total]=head[x]; head[x]=total; return ; } int tot=0; int dfn[1000006]; int low[1000006]; int sta[1000006]; int book[1000006]; int set=0; int color[1000006]; int cnt=0; void tarjan(int x){ low[x]=dfn[x]=++tot; sta[++set]=x; book[x]=1; for(int e=head[x];e;e=nxt[e]){ if(!dfn[to[e]]){ tarjan(to[e]); low[x]=min(low[x],low[to[e]]); } else if(book[to[e]]) low[x]=min(low[x],dfn[to[e]]); } if(dfn[x]==low[x]){ book[x]=0; cnt++; color[x]=cnt; while(sta[set]!=x){ book[sta[set]]=0; color[sta[set]]=cnt; set--; } set--; } return ; } int du[1000006]; int du2[1000006]; int main(){ n=rd(); for(int i=1;i<=n;i++){ int x; while(x=rd()) add(i,x); } for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); for(int i=1;i<=n;i++){ for(int e=head[i];e;e=nxt[e]){ if(color[i]!=color[to[e]]){ du[color[to[e]]]++; du2[color[i]]++; } } } int ans=0; int num=0; for(int i=1;i<=cnt;i++){ if(du[i]==0) ans++; if(du2[i]==0) num++; } write(ans);puts(""); write(cnt==1?0:max(ans,num)); return 0; }