题目大意:
给一个有向图,一个文件可以从某个点出发传递向他能连的边
现在有两个问题
1.至少需要多少个放文件可以让整个图都有文件
2.可以进行一个操作:给一对点(u,v)连一条u->v的有向边,问至少需要多少次操作,才能使任意一个点放的文件都能传递到整个图
题解:
先tarjan缩个点
对于1. 找入度为0的强联通分量的个数
对于2.取出度和入度为0的强联通分量的个数的较大值(如果只有一个,显然是0)
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<vector> 5 #include<stack> 6 #define M 50010 7 #define N 10010 8 using namespace std; 9 int n,m,u,v,head[N],cnt=1,ans,in[N],belong[N],dfn[N],low[N],indx,tar,out[N]; 10 bool inst[N]; 11 stack <int> st; 12 struct edge 13 { 14 int u,v; 15 }e[M]; 16 void add(int u,int v) 17 { 18 e[cnt].v=v; 19 e[cnt].u=head[u]; 20 head[u]=cnt++; 21 } 22 void dfs(int u) 23 { 24 dfn[u]=low[u]=++indx; 25 inst[u]=1; 26 st.push(u); 27 for (int i=head[u];i;i=e[i].u) 28 { 29 int v=e[i].v; 30 if(!dfn[v]) 31 { 32 dfs(v); 33 low[u]=min(low[u],low[v]); 34 } 35 else 36 if (inst[v]) 37 low[u]=min(low[u],dfn[v]); 38 } 39 if (dfn[u]==low[u]) 40 { 41 tar++; 42 while (1) 43 { 44 int t=st.top(); 45 st.pop(),inst[t]=0; 46 belong[t]=tar; 47 if (t==u) 48 break; 49 } 50 } 51 } 52 int main() 53 { 54 scanf("%d",&n); 55 for (int i=1;i<=n;i++) 56 { 57 int j; 58 while (scanf("%d",&j)!=EOF && j!=0) 59 add(i,j); 60 } 61 for (int i=1;i<=n;i++) 62 if (dfn[i]==0) dfs(i); 63 for (int i=1;i<=n;i++) 64 for (int j=head[i];j;j=e[j].u) 65 { 66 int v=e[j].v; 67 if (belong[i]!=belong[v]) 68 { 69 // printf("%d %d ",i,v); 70 in[belong[v]]++; 71 out[belong[i]]++; 72 } 73 } 74 for (int i=1;i<=tar;i++) 75 if (in[i]==0) ans++; 76 printf("%d ",ans); 77 int ans2=0; 78 for (int i=1;i<=tar;i++) 79 if (out[i]==0 && tar>1) ans2++; 80 if (tar==1) ans=0; 81 printf("%d ",max(ans,ans2)); 82 return 0; 83 }