http://acm.hdu.edu.cn/showproblem.php?pid=2767
今天在做图论专题的时候碰到了这题,这样的话,正好学习了来写篇博客吧
题目意思就是,给你一个有向网络图,问,至少加多少条边能使这个图成强连通
那么就是要,先把图跑一遍targan,如果这个图是强连通,那么就输出0了,否则缩点,然后求所有点入度为0和出度为0个数的最大值了
主要理解的地方就是缩点的那个地方,要理解belong数组的含义,以及为什么是求入度0和出席0的最大值
证明我是不知道= =,真的是只能意会么 ?
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn(55555); int low[maxn], dfn[maxn], vis[maxn], belong[maxn]; struct Edge{ int v, next; }e[maxn]; int head[maxn], cnt; int n, m; int step, color; int stack[maxn], top; void targan(int u){ low[u] = dfn[u] = ++ step; vis[u] = 1; stack[top++] = u; for(int i = head[u]; i + 1; i = e[i].next){ int v = e[i].v; //printf("-- %d %d\n", u, v); if(!dfn[v]){ targan(v); low[u] = min(low[u], low[v]); }else if(vis[v]) low[u] = min(low[u], dfn[v]); } if(dfn[u] == low[u]){ color ++; int s; do{ s = stack[--top]; vis[s] = 0; belong[s] = color; }while(u != s); } } int in[maxn], out[maxn]; #define clr(a) memset(a, 0, sizeof a) void init(){ clr(dfn); clr(vis); clr(low); clr(belong); clr(in); clr(out); top = step = color = cnt = 0; memset(head, -1, sizeof head); } void add_Edge(int u, int v){ e[cnt].v = v, e[cnt].next = head[u]; head[u] = cnt ++; } void solve(){ for(int i = 1; i <= n; i ++) if(!dfn[i]) targan(i); if(color == 1){ puts("0"); return; } for(int i = 1; i <= n; i ++){ for(int j = head[i]; j + 1; j = e[j].next){ int v = e[j].v; if(belong[i] != belong[v]){ in[belong[v]]++; out[belong[i]] ++; } } } int a = 0, b = 0; for(int i = 1; i <= color; i ++){ if(in[i] == 0) a ++; if(out[i] == 0) b ++; } printf("%d\n", max(a, b)); } int main(){ int tcase; scanf("%d", &tcase); while(tcase --){ scanf("%d%d", &n, &m); if(m == 0){ printf("%d\n", n); continue; } init(); while(m--){ int u, v; scanf("%d%d", &u, &v); add_Edge(u, v); } solve(); } return 0; }