题意:给出一个有向图。1:问至少选出多少个点,才能沿有向边遍历所有节点。2:问至少加多少条有向边,使原图强连通。
分析:第一个问题,缩点后找所有树根(入度为0)。第二个问题,分别找出入度为0和出度为0的所有点,去最大值即为答案。
关于第二个问题,与这道题很相似。
1 #include<cstdio> 2 #include<cstring> 3 #include<stack> 4 #include<algorithm> 5 using namespace std; 6 7 const int MAXN=111; 8 9 struct Edge{ 10 int v,next; 11 Edge(){} 12 Edge(int _v,int _next):v(_v),next(_next){} 13 }edge[MAXN*MAXN]; 14 15 int pre[MAXN],low[MAXN],sccno[MAXN],dfs_clock,scc_cnt; 16 int head[MAXN],tol; 17 18 int outmark[MAXN],inmark[MAXN]; 19 20 stack<int>stk; 21 22 void init() 23 { 24 tol=0; 25 memset(head,-1,sizeof(head)); 26 } 27 28 void add(int u,int v) 29 { 30 edge[tol]=Edge(v,head[u]); 31 head[u]=tol++; 32 } 33 34 void dfs(int u) 35 { 36 int v; 37 pre[u]=low[u]=++dfs_clock; 38 stk.push(u); 39 for(int i=head[u];i!=-1;i=edge[i].next) 40 { 41 v=edge[i].v; 42 43 if(!pre[v]){ 44 dfs(v); 45 low[u]=min(low[u],low[v]); 46 }else if(!sccno[v]) 47 low[u]=min(low[u],pre[v]); 48 } 49 if(pre[u]==low[u]){ 50 scc_cnt++; 51 do{ 52 v=stk.top(); 53 stk.pop(); 54 sccno[v]=scc_cnt; 55 }while(u!=v); 56 } 57 } 58 59 void find_scc(int n) 60 { 61 dfs_clock=scc_cnt=0; 62 memset(pre,0,sizeof(pre)); 63 memset(low,0,sizeof(low)); 64 memset(sccno,0,sizeof(sccno)); 65 66 for(int i=1;i<=n;i++) 67 if(!pre[i]) 68 dfs(i); 69 } 70 71 int main() 72 { 73 int n; 74 scanf("%d",&n); 75 init(); 76 for(int u=1;u<=n;u++) 77 { 78 while(1) 79 { 80 int v; 81 scanf("%d",&v); 82 if(!v) 83 break; 84 add(u,v); 85 } 86 } 87 88 find_scc(n); 89 90 memset(inmark,0,sizeof(inmark)); 91 memset(outmark,0,sizeof(outmark)); 92 for(int i=1;i<=n;i++) 93 { 94 for(int j=head[i];j!=-1;j=edge[j].next) 95 if(sccno[i]!=sccno[edge[j].v]){ 96 inmark[sccno[edge[j].v]]++; 97 outmark[sccno[i]]++; 98 } 99 } 100 int inans=0,outans=0; 101 for(int i=1;i<=scc_cnt;i++) 102 { 103 if(!inmark[i]) 104 inans++; 105 if(!outmark[i]) 106 outans++; 107 } 108 printf("%d ",inans); 109 if(scc_cnt==1) 110 printf("0 "); 111 else 112 printf("%d ",max(inans,outans)); 113 return 0; 114 }