题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3836;
题意:大致是给一个有向图,问加几条边能成为强连通图。
分析:先对此图进行强连通分量求解,然后要缩点,千万要记住缩完点之后要从新链接图,连完之后就有有点没有入度,有点没有出度;但强连通图内所有点都有入入度和出度,所以按缺失点增加一个出度或一个入度,最后一定是入度等于出度所以求解最大值即可,但有一点,强连通分量为1的时候不需增加边(做完心好累)。
代码:
#include <set> #include <map> #include <stack> #include <queue> #include <math.h> #include <vector> #include <string> #include <utility> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <iostream> #include <algorithm> #include <functional> using namespace std; long long V; //定点数 vector<long long> G[100050]; //正向建图 vector<long long> rG[100050]; //反向建图 vector<long long> vs; //遍历的顺序 bool used[100050]; long long cmp[100050]; //强连通分量的拓扑序 void add_edge(long long from,long long to){ G[from].push_back(to); rG[to].push_back(from); } void dfs(long long v){ long long i; used[v]=1; for(i=0;i<G[v].size();i++) if(!used[G[v][i]]) dfs(G[v][i]); vs.push_back(v); } void rdfs(long long v,long long k){ long long i; used[v]=1; cmp[v]=k; for(i=0;i<rG[v].size();i++) //只有强连通分量才不受反向建边 if(!used[rG[v][i]]) //的影响,因此找出强连通分量的 rdfs(rG[v][i],k); //同时,找出强连通分量的拓扑序 } long long scc(){ long long i,k; memset(used,0,sizeof(used)); vs.clear(); for(i=0;i<V;i++) if(!used[i]) dfs(i); memset(used,0,sizeof(used)); k=0; for(i=vs.size()-1;i>=0;i--) //拓扑序最小的点在容器vs的最后面 if(!used[vs[i]]) rdfs(vs[i],k++); return k; } long long x[100500],y[100500]; int main(){ while(scanf("%I64d",&V)!=EOF){ long long m; scanf("%I64d",&m); for(long long i=0;i<V;i++){ G[i].clear(); rG[i].clear(); cmp[i]=i; } for(long long i=0;i<m;i++){ scanf("%I64d%I64d",&x[i],&y[i]); if(x[i]!=y[i]) add_edge(x[i]-1,y[i]-1); } long long s=scc(); for(long long i=0;i<V;i++){ G[i].clear(); rG[i].clear(); } for(long long i=0;i<m;i++){ if(cmp[x[i]-1]!=cmp[y[i]-1]){ add_edge(cmp[x[i]-1],cmp[y[i]-1]); } } if(s==1){ cout<<0<<endl; continue; }//强连通分量为1时 // cout<<sum<<endl; long long sum1,sum2; sum1=sum2=0; for(int i=0;i<s;i++){ if(G[i].size()==0) sum1++; if(rG[i].size()==0) sum2++; } cout<<max(sum1,sum2)<<endl; } return 0; }