1. 程式人生 > 其它 >P2812 校園網路【[USACO]Network of Schools加強版】

P2812 校園網路【[USACO]Network of Schools加強版】

技術標籤:P2812校園網路

文章目錄

R e s u l t Result Result

...


H y p e r l i n k Hyperlink Hyperlink

https://www.luogu.com.cn/problem/P2812


D e s c r i p t i o n Description
Description

n n n個學校, m m m條單項線路,一條線路 ( x , y ) (x,y) (x,y)連線了 x , y x,y x,y,使得 x x x能共享軟體給 y y y

問最少選幾個學校,使得所有學校都能共享軟體
最少新增幾條線路,可以使得任意學校都能為其他學校共享軟體

資料範圍: n ≤ 1 0 4 , m ≤ 5 × 1 0 6 n\leq 10^4,m\leq 5\times 10^6 n104,m5×106


S o l u t i o n Solution Solution

首先一個強聯通分量內的學校隨便選一個,整個連通分量就都共享了,所以我們先縮點

第一問顯然就是縮點之後入讀為0的點的個數

第二問則是入度為0的點和出度為0的點的最大值(兩兩匹配)

時間複雜度: O ( n + m ) O(n+m) O(n+m)


C o d e Code Code

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#define LL long long
#define N 10010
#define M 5000010
using namespace std;int n,l[N],tot,m;
struct node{int next,
to;}e[M]; inline void add(int u,int v){e[++tot]=(node){l[u],v};l[u]=tot;return;} inline LL read() { char c;LL d=1,f=0; while(c=getchar(),!isdigit(c)) if(c=='-') d=-1;f=(f<<3)+(f<<1)+c-48; while(c=getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48; return d*f; } int x,dfn[N],low[N],stk[N],top,cnt,which[N],siz[N],rd[N],cd[N]; bool vis[N]; inline void Tarjan(int x) { dfn[x]=low[x]=++cnt;vis[x]=true;stk[++top]=x; for(register int i=l[x];i;i=e[i].next) { int y=e[i].to; if(dfn[y]==0) { Tarjan(y); low[x]=min(low[x],low[y]); } else if(vis[y]) low[x]=min(low[x],dfn[y]); } if(dfn[x]==low[x]) { int y; while(y=stk[top--]) { siz[x]++; which[y]=x;vis[y]=false; if(y==x) break; } } } signed main() { n=read(); for(register int i=1;i<=n;i++) { while(x=read(),x) add(i,x); } for(register int i=1;i<=n;i++) if(!dfn[i]) Tarjan(i); for(register int i=1;i<=n;i++) for(register int j=l[i];j;j=e[j].next) if(which[i]!=which[e[j].to]) rd[which[e[j].to]]++,cd[which[i]]++; int tot=0,ans=0,gs=0; for(register int i=1;i<=n;i++) if(which[i]==i) tot+=rd[i]==0,ans+=cd[i]==0,gs++; if(gs>1) printf("%d\n%d",tot,max(ans,tot));else puts("1\n0"); }