题意:给定一个有向图,求最少要从几个结点开始能把图遍历完,最少添加多少条边,使得整个图强连通。
先缩点,然后对于缩点以后的图,入度为0的点的个数就是第一问的解,第二问的解是入度为0结点个数和出度为0结点个数中的最大值,第二问参考的解题报告是:http://hi.baidu.com/oichampion/blog/item/1882abd7d86adec5a9ec9aa5.html
代码:
#include<iostream> #include<cstring> #include<cstdio> #include<vector> #include<stack> using namespace std; #define MIN(a,b) a>b?b:a #define MAX(a,b) a<b?b:a const int MAXN = 110; int sg[MAXN][MAXN],vis[MAXN],dfn[MAXN],low[MAXN],belong[MAXN],indeg[MAXN],outdeg[MAXN],scnt,deep; vector<int> g[MAXN]; stack<int> S; void init() { memset(belong,-1,sizeof(belong)); memset(vis,0,sizeof(vis)); memset(sg,0,sizeof(sg)); memset(indeg,0,sizeof(indeg)); memset(outdeg,0,sizeof(outdeg)); for(int i=0;i<MAXN;i++)g[i].clear(); while(!S.empty())S.pop();scnt=0;deep=0; } void tarjan(int u,int &deep) { low[u] = dfn[u] = deep; vis[u] = 1;S.push(u);deep++; for(int i=0;i<g[u].size();i++) { int v = g[u][i]; if(!vis[v]) { tarjan(v,deep); low[u] = MIN(low[u],low[v]); } else if(belong[v]==-1) { low[u] = MIN(low[u],dfn[v]); } } if(low[u]==dfn[u]) { int v; do { v = S.top(); S.pop(); belong[v] = scnt; }while(v!=u); scnt++; } } void getscc(int n) { for(int i=1;i<=n;i++) { if(!vis[i])tarjan(i,deep); } } void getsg(int n)//获得缩点图 { for(int i=1;i<=n;i++) { for(int j=0;j<g[i].size();j++) { if(belong[i]!=belong[g[i][j]]) { sg[belong[i]][belong[g[i][j]]]=1; } } } } void cacsgindeg()//计算缩点图的入度 { for(int i=0;i<scnt;i++) { for(int j=0;j<scnt;j++) { if(sg[j][i])indeg[i]++; if(sg[i][j])outdeg[i]++; } } } int getzerodeg() { int cnt = 0; for(int i=0;i<scnt;i++) { if(indeg[i]==0)cnt++; } return cnt; } int getzeroout() { int cnt = 0; for(int i=0;i<scnt;i++) { if(outdeg[i]==0)cnt++; } return cnt; } int main() { int n; while(scanf("%d",&n)!=EOF) { int u;init(); for(int i=1;i<=n;i++) { while(scanf("%d",&u),u) { g[i].push_back(u); } } getscc(n); getsg(n); cacsgindeg(); int copy = getzerodeg(),edge = MAX(copy,getzeroout()); if(scnt!=1){ printf("%d\n%d\n",copy,edge); }else printf("1\n0\n"); } return 0; }