题目大意:
N台电脑之间能够通过有向边(u,v)从第u台电脑传输文件到第v台电脑。如果给第u台电脑投放一个文件,那么这个文件就能通过有向边传输到第v台电脑上,给你N台电脑的连接情况。那么问题来了:1、最少向这N台电脑中的几台电脑投放文件,就能使N台电脑都能接收到文件。2、最少向这N台电脑构成的图中添加几条边,使只向任何一台电脑投放文件,就能够让N台电脑接收到文件。
样例输入:
5 2 4 3 0 4 5 0 0 0 1 0
样例输出:
1 2
题解:
首先tarjan缩点,第一问就是问有多少个入度为0的点,第二问就是问至少加多少条边使得这有向图变成一个强连通分量。
主要问题在第二问,一个强连通分量中所有点一定有出度与入度(除法就一个点),因此缩点后的图中所有入度或者出度为0的点都要加边,每次边可以从一个出度为0的点连向入度为0的点,因为答案为min(numin,numout)
提醒多组数据
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstring> 4 #include<cstdio> 5 struct node 6 { 7 int next,to; 8 } e[200005]; 9 int head[1005],dfn[1005],low[1005],in[1005],out[1005],vis[1005]; 10 int cnt,time,s[1005],bl[1005],sc; 11 using namespace std; 12 inline void insert(int u,int v) 13 { 14 e[++cnt].next=head[u]; 15 head[u]=cnt; 16 e[cnt].to=v; 17 } 18 inline void init() 19 { 20 memset(head,0,sizeof(head)); 21 memset(in,0,sizeof(in)); 22 memset(out,0,sizeof(out)); 23 memset(low,0,sizeof(low)); 24 memset(vis,0,sizeof(vis)); 25 memset(dfn,0,sizeof(dfn)); 26 memset(bl,0,sizeof(bl)); 27 memset(s,0,sizeof(s)); 28 } 29 inline void tarjan(int now) 30 { 31 dfn[now]=low[now]=++time; 32 s[++s[0]]=now,vis[now]=1; 33 for(int i=head[now];i;i=e[i].next) 34 { 35 if(!dfn[e[i].to]) 36 { 37 tarjan(e[i].to); 38 low[now]=min(low[now],low[e[i].to]); 39 } 40 else if(vis[e[i].to]) 41 low[now]=min(low[now],dfn[e[i].to]); 42 } 43 if(low[now]==dfn[now]) 44 { 45 bl[now]=++sc; 46 vis[now]=0; 47 while(s[s[0]]!=now) 48 { 49 bl[s[s[0]]]=sc; 50 vis[s[s[0]]]=0; 51 s[0]--; 52 } 53 s[0]--; 54 } 55 } 56 int main() 57 { 58 int n,v; 59 while(scanf("%d",&n)!=EOF) 60 { 61 init(); 62 cnt=time=sc=0; 63 for(int i=1;i<=n;i++) 64 while(scanf("%d",&v) && v) 65 insert(i,v); 66 for(int i=1;i<=n;i++) 67 if(!dfn[i]) tarjan(i); 68 for(int i=1;i<=n;i++) 69 for(int j=head[i];j;j=e[j].next) 70 { 71 if(bl[i]!=bl[e[j].to]) 72 out[bl[i]]++,in[bl[e[j].to]]++; 73 } 74 int numin=0,numout=0; 75 for(int i=1;i<=sc;i++) 76 { 77 if(!in[i]) numin++; 78 if(!out[i]) numout++; 79 } 80 if(sc==1) printf("1\n0\n"); 81 else printf("%d\n%d\n",numin,max(numin,numout)); 82 } 83 }