题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2767
题目大意:给定一张有向图,问最少添加几条边使得有向图成为一个强连通图。
解题思路:图论真心不会做啊,看了别人的解题报告之后发现大家都用一句话概括解法:缩点后找入度为0的点和出度为0的点,统计个数,选择大的那个数就是答案。我檫嘞,有这么显然嘛?想了一下,如果出度为0的个数n比入度为0的个数m多,那添加n条边,从当前出度为0的点到其他入度为0的点,肯定能成为强连通图,同理可得m大也Ok。果然很明显啊,喝喝..
本题有个Trick,如果压缩后的点个数为1,那么无需增加边。
测试数据:
10
代码:
#include <stdio.h> #include <string.h> #define MIN 21000 #define MAX 51000 #define min(a,b) (a)<(b)?(a):(b) struct node { int v; node *next; }*head[MAX],tree[MAX]; int totin[MIN],totout[MIN]; int dfn[MIN],low[MIN],st[MIN]; int numin,numout,isstack[MIN]; int ptr,index,top,ans,tot,bl[MIN]; void Initial() { index = top = ptr = 1; tot = numin = numout = 0; memset(dfn,0,sizeof(dfn)); memset(totin,0,sizeof(totin)); memset(head,NULL,sizeof(head)); memset(totout,0,sizeof(totout)); } void AddEdge(int x,int y) { tree[ptr].v = y; tree[ptr].next = head[x],head[x] = &tree[ptr++]; } void Trajan (int i) { node *p = head[i]; st[++top] = i; isstack[i] = 1; dfn[i] = low[i] = index++; while (p != NULL) { if (!dfn[p->v]) { Trajan(p->v); low[i] = min(low[i],low[p->v]); } else if (isstack[p->v]) low[i] = min(low[i],dfn[p->v]); p = p->next; } if (dfn[i] == low[i]) { tot++; int v = -1; while (v != i) { v = st[top--]; bl[v] = tot; isstack[v] = 0; } } } int main() { int n,m,a,b,i,t; int from[MAX],to[MAX]; scanf("%d",&t); while (t--) { Initial(); scanf("%d%d",&n,&m); for (i = 1; i <= m; ++i) { scanf("%d%d",&a,&b); AddEdge(a,b); from[i] = a,to[i] = b; } for (i = 1; i <= n; ++i) if (!dfn[i]) Trajan(i); if (tot == 1) { printf("0\n"); continue; } for (i = 1; i <= m; ++i) { int x = bl[from[i]],y = bl[to[i]]; if (x != y) totout[x]++,totin[y]++; } for (i = 1; i <= tot; ++i){ if (!totin[i]) numin++; if (!totout[i]) numout++; } ans = numin > numout ? numin : numout; printf("%d\n",ans); } return 0; }
本文ZeroClock原创,但可以转载,因为我们是兄弟。