IOI 1996 網絡協議
阿新 • • 發佈:2018-11-02
book write sta algo 過程 lin stream pac nbsp
一些學校連接在一個計算機網絡上。學校之間存在軟件支援協議。每個學校都有它應支援的學校名單(學校 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; }
IOI 1996 網絡協議