Description
Input
Output
Sample Input
5 2 4 3 0 4 5 0 0 0 1 0
Sample Output
1 2
Source
题目大意:给定一个有向图,求至少要有多少个点, 才能从这些点出发到达所有点;至少要添加多少条边,才能从任意一点出发到达所有点
首先要推出一个定理:在DAG中,对于所有入度不为0的点,一定有入度为0的点可达(因为从入度为0的点倒着走,一定能走到入度不为0的点)
于是此题可用tarjan缩点,求有多少个入度为0的点,这就是第一个问题的答案。
第二个问题的答案为入度为0的点和出度为0的点的最小值,证明比较难,略。
对于这道题,因为只要求入度和出度为0的点,故只需在tarjan过程中记录每个点归属哪个强连通分量,然后统计输出即可
#include <iostream> #include <stdio.h> #include <string.h> #define MAXE 500 #define MAXV 3000 using namespace std; int N; struct edge { int u,v,next; }edges[MAXV]; int head[MAXE],nCount=0; int dfn[MAXE],low[MAXE],index=0; int belong[MAXE],tot=0; //belong[i]=i点所属的强连通分量,tot=强连通分量总数 bool inStack[MAXE]; int stack[MAXE*4],top=0; bool map[MAXE][MAXE]; int inDegree[MAXE],outDegree[MAXE],inZero=0,outZero=0; //入度,出度 int max(int a,int b) { if(a>b) return a; return b; } int min(int a,int b) { if(a<b) return a; return b; } void AddEdge(int U,int V) { edges[++nCount].u=U; edges[nCount].v=V; edges[nCount].next=head[U]; head[U]=nCount; } void tarjan(int u) { dfn[u]=low[u]=++index; stack[++top]=u; //该点入栈 inStack[u]=true; for(int p=head[u];p!=-1;p=edges[p].next) { int v=edges[p].v; if(!dfn[v]) { tarjan(v); low[u]=min(low[u],low[v]); } else if(inStack[v]) { low[u]=min(low[u],dfn[v]); } } int v; if(dfn[u]==low[u]) { tot++; do { v=stack[top--]; belong[v]=tot; inStack[v]=false; } while(u!=v); } } int main() { int to; cin>>N; memset(head,-1,sizeof(head)); for(int i=1;i<=N;i++) { while(1) { cin>>to; if(to==0) break; AddEdge(i,to); map[i][to]=true; } } for(int i=1;i<=N;i++) if(!dfn[i]) tarjan(i); for(int i=1;i<=N;i++) for(int j=1;j<=N;j++) { if(map[i][j]&&belong[i]!=belong[j]) { inDegree[belong[j]]++; outDegree[belong[i]]++; } } for(int i=1;i<=tot;i++) { if(!inDegree[i]) inZero++; if(!outDegree[i]) outZero++; } if(tot==1) cout<<1<<endl<<0<<endl; else cout<<inZero<<endl<<max(inZero,outZero)<<endl; return 0; }