链接:http://acm.hdu.edu.cn/showproblem.php?pid=3836
给你N个点,M条边的有向图,让你求加最少的边,使得该图 成为强连通图
思路:
找出所有强连通分量,若连通分量数为1,ans = 0;
否则缩点,若要使缩点后的图为强连通图,每个点至少入度和出度都为1,而一条边提供一个入度和一个出度 :答案就是入度为0 和 出度为0 的分量数的最大值。
网赛现学的 tarjin+缩点 还行,不难 ,浪费了好多时间 这次要好好补题了
#include<bits/stdc++.h> using namespace std; const int N = 1e6; #define mem(a,b) memset(a,b,sizeof(a)) int n,m,ti,scc; struct node { int from,to,next; }e[N]; int head[N],dfn[N],vis[N],low[N],in[N],out[N],col[N]; stack<int>s; void init() { while (!s.empty()) s.pop(); ti = 0; scc = 0; mem(head,-1); mem(dfn,0); mem(vis,0); mem(low,0); mem(in,0); mem(out,0); mem(col,0); } void tarjan(int u) { vis[u] = 1;//在栈里面 s.push(u); dfn[u] = low[u] = ++ti;//时间戳这里是++ 不然容易出现 dfn[u] = 0 情况 这样子 for(int i=head[u];i != -1;i = e[i].next) { int v = e[i].to; if(!dfn[v]) { tarjan(v); low[u] = min(low[u],low[v]); } else if(vis[v]) { low[u] = min(low[u],dfn[v]); } } if(dfn[u] == low[u] )//关键点 { int x; scc++; do{ x = s.top(); s.pop(); vis[x] =0; col[x] = scc;//分类 强连通分量 }while (x != u); } } int main() { while (~scanf("%d %d",&n,&m) && n+m) { init(); for(int i=0;i<m;i++) { int x,y; scanf("%d %d",&x,&y); e[i].from = x; e[i].to = y; e[i].next = head[x]; head[x] = i; } for(int i=1;i<=n;i++) { if(!dfn[i]) tarjan(i); } //cout<< "scc"<<scc<<endl; for(int i=0;i<m;i++) { int u = e[i].from, v= e[i].to; if(col[u] != col[v]) { in[col[v]] ++; out[col[u]]++; } } int ans1=0,ans2=0; for(int i=1;i<=scc;i++) { if(!in[i]) ans1++; if(!out[i]) ans2++; //cout<< in[i] <<" "<<out[i]<<endl; } if(scc == 1)//已经是连通图了 { cout<< 0 <<endl; continue; } cout<< max (ans1,ans2)<<endl; } }