UVAlive4287_Proving Equivalences

题意是告诉你有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;
}
posted @ 2014-07-17 23:44  092000  阅读(372)  评论(0编辑  收藏  举报