1. 程式人生 > >P2746 [USACO5.3]校園網Network of Schools

P2746 [USACO5.3]校園網Network of Schools

%d 一個 getch space target ref printf lock lan

傳送門

把所有學校的關系構成一個圖,顯然一個強聯通分量的所有學校只要有一個有新軟件,其他學校也都會有

考慮縮點,發現入度為 0 的塊一定要給,因為沒有其他人給它

入度不為 0 的塊一定有其他人給,我們只要給 能給它的塊 提供軟件就可以了

所以就是入度為 0 的塊一定給,不為 0 的塊一定不用給

子任務A就是求出入度為 0 的塊的數量

然後考慮子任務B

顯然出度為 0 的塊一定要連邊出去,入度為 0 的塊也一定要有邊連過來

所以出度為 0 的塊連給誰呢,當然給入度為 0 的塊

所以就是求 出度為 0 的塊數量 和 入度為 0 的塊的數量的較大值

當然別忘了特判整個圖本身就是聯通塊的情況

#include<iostream>
#include
<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<0||ch>9) { if(ch==-) f=-1; ch=getchar(); } while(ch>=0&&ch<=9) { x=(x<<1)+(x<<3
)+(ch^48); ch=getchar(); } return x*f; } const int N=1007; int n; int fir[N],from[N<<1],to[N<<1],cntt; inline void add(int &a,int &b) { from[++cntt]=fir[a]; fir[a]=cntt; to[cntt]=b; } //Tarjan模板 int dfs_clock,dfn[N],low[N],st[N],Top; int bel[N],tot;//存每個點屬於哪個塊
void Tarjan(int x) { dfn[x]=low[x]=++dfs_clock; st[++Top]=x; for(int i=fir[x];i;i=from[i]) { int &v=to[i]; if(!dfn[v]) Tarjan(v),low[x]=min(low[x],low[v]); else if(!bel[v]) low[x]=min(low[x],dfn[v]); } if(low[x]==dfn[x]) { tot++; while(st[Top]!=x) { bel[st[Top]]=tot; Top--; } bel[x]=tot; Top--; } } int in[N],out[N],ans1,ans2;//入度,出度,入度為0的數量和出度為0的數量 inline void build()//計算in,ouw,ans1,ans2 { for(int i=1;i<=n;i++) for(int j=fir[i];j;j=from[j]) { int &t=to[j]; if(bel[i]==bel[t]) continue;//同塊內不考慮 out[bel[i]]++; in[bel[t]]++; } for(int i=1;i<=tot;i++) { if(!in[i]) ans1++; if(!out[i]) ans2++; } } int main() { int a; n=read(); for(int i=1;i<=n;i++) { a=read(); while(a) add(i,a),a=read(); } for(int i=1;i<=n;i++) if(!bel[i]) Tarjan(i); build(); if(tot==1) printf("%d\n%d",1,0);//特判 else printf("%d\n%d",ans1,max(ans1,ans2)); return 0; }

P2746 [USACO5.3]校園網Network of Schools