题意是告诉你有n个命题,m条递推关系,表示某个命题可以推出另外一个命题。
现在问你至少在增加多少个递推关系可以保证所有命题两两互推。
命题为点,关系为有向边,题目转化成为至少增加多少条有向边使得整个图强连通。
首先对于有向图,求出所有的联通分量,并且将所有的联通分量缩成一个点,最终得出一个无环图。
在新图里,设有A个出度为0的点,B个入度为0的点,那么我们只要保证增加max(A,B)条边就可以保证整个图是强连通的。
这个理解不是很难,只要把所有出度为0的点引出一条边,保证每个入度为0的点引入一条边就可以了。
召唤代码君:
#include <iostream> #include <cstring> #include <cstdio> #define maxn 200200 using namespace std; int first[maxn],to[maxn],next[maxn],edge; int d[maxn],low[maxn],belong[maxn],stack[maxn],top; int ind[maxn],outd[maxn],U[maxn],V[maxn]; int n,m,T,scc,ans1,ans2; void _init() { ans1=ans2=scc=top=0,edge=-1; for (int i=1; i<=n; i++) { first[i]=-1; d[i]=low[i]=belong[i]=0; } } void addedge(int uu,int vv) { edge++; to[edge]=vv,next[edge]=first[uu],first[uu]=edge; } void dfs(int cur,int fa) { d[cur]=low[cur]=d[fa]+1; stack[++top]=cur; for (int i=first[cur]; i!=-1; i=next[i]) { if (belong[to[i]]) continue; if (!d[to[i]]) dfs(to[i],cur); low[cur]=min(low[cur],low[to[i]]); } if (low[cur]>=d[cur]) for (scc++,ind[scc]=outd[scc]=0;stack[top+1]!=cur;) belong[stack[top--]]=scc; } int main() { scanf("%d",&T); while (T--) { scanf("%d%d",&n,&m); _init(); for (int i=1; i<=m; i++) { scanf("%d%d",&U[i],&V[i]); addedge(U[i],V[i]); } for (int i=1; i<=n; i++) if (!d[i]) dfs(i,0); for (int i=1; i<=m; i++) { if (belong[U[i]]==belong[V[i]]) continue; outd[belong[U[i]]]++; ind[belong[V[i]]]++; } for (int i=1; i<=scc; i++) { if (ind[i]==0) ans1++; if (outd[i]==0) ans2++; } if (scc==1) ans1=ans2=0; printf("%d\n",max(ans1,ans2)); } return 0; }
UVAlive4287_Proving Equivalences,布布扣,bubuko.com
UVAlive4287_Proving Equivalences
原文地址:http://www.cnblogs.com/Canon-CSU/p/3852438.html