hdu3836

来源:互联网 发布:超级基因优化液微盘 编辑:程序博客网 时间:2024/04/29 23:07

Equivalent Sets

Time Limit: 12000/4000 MS (Java/Others)    Memory Limit: 104857/104857 K (Java/Others)
Total Submission(s): 3751    Accepted Submission(s): 1308


Problem Description
To prove two sets A and B are equivalent, we can first prove A is a subset of B, and then prove B is a subset of A, so finally we got that these two sets are equivalent.
You are to prove N sets are equivalent, using the method above: in each step you can prove a set X is a subset of another set Y, and there are also some sets that are already proven to be subsets of some other sets.
Now you want to know the minimum steps needed to get the problem proved.
 

Input
The input file contains multiple test cases, in each case, the first line contains two integers N <= 20000 and M <= 50000.
Next M lines, each line contains two integers X, Y, means set X in a subset of set Y.
 

Output
For each case, output a single integer: the minimum steps needed.
 

Sample Input
4 03 21 21 3
 

Sample Output
4

2

一个图,含有n个点,p条边(单向),问最少加几条边可以使该图成为强连通图,

可以用Tarjan算法,或者Kosaraju算法,算出含有几个强连通分量,这几个强连通分量有有几个出度为0有几个入度为0,输出多的那个(a个出度为0的分量,b个入度为0 的分量,输出max(a,b));

解释:强连通分量里每个点都是可以互相到达的,每个强连通分量之间要想都可以互相到达,每个分量必须至少含有一个出度一个入度,也就是说,出度为0的边必须给他加一条边指向其他分量,如果入度为0 ,那么要给他加一条边指向他,所以出 输出max(a,b)

注意:如果只有一个强连通分量,或者n==1,输出0,因为一个强连通分量表示该图就是强连通的了,,n==1时自身可以到达自身,也是强连通图,

#include <iostream>#include <stdio.h>#include <string.h>#include <math.h>using namespace std;const int maxn=20020;const int maxe=50040;struct edge{    int x,y,next;} e[maxe];int num[maxn];///每个联通分量含有点的个数int g[maxn],f[maxn];///f入度,g出度int dfn[maxn],low[maxn],v[maxn],s[maxn],b[maxn],h[maxn];int n,tot=0,cnt=0,ans=0,ans2,times,t;void init(){    tot=0;    memset(h,0,sizeof(h));}void ins(int x,int y) ///tot 从1开始{    e[++tot].x=x;    e[tot].y=y;    e[tot].next=h[x];    h[x]=tot;}int max(int a,int b){    if(a>b)        return a;    return b;}int min(int a,int b){    if(a<b)        return a;    return b;}void Tarjan(int x){    int y,i;    times++;    t++;    dfn[x]=low[x]=times;    v[x]=1;    s[t]=x;    for (i=h[x]; i; i=e[i].next)    {        y=e[i].y;        if (v[y]==0)        {            Tarjan(y);            low[x]=min(low[x],low[y]);        }        if (v[y]==1)            low[x]=min(low[x],dfn[y]);    }    if (dfn[x]==low[x])    {        cnt++;        do        {            y=s[t--];            b[y]=cnt;///属于哪个强连通分量            v[y]=2;            // num[cnt]++;        }        while (y!=x);    }}void solve(){    times=0;    t=0;    cnt=0;///连通分量个数    memset(dfn,0,sizeof(dfn));    //memset(num,0,sizeof(num));    memset(v,0,sizeof(v));    for(int i=1; i<=n; i++)        if(!dfn[i])            Tarjan(i);}int main(){    int x,y;    int p;    while(scanf("%d%d",&n,&p)!=-1)    {        if(n==1)        {            cout<<0<<endl;            continue;        }        init();        for(int i=0; i<p; i++)        {            scanf("%d%d",&x,&y);            ins(x,y);        }        solve();        memset(f,0,sizeof(f));        memset(g,0,sizeof(g));        for (int i=1; i<=tot; i++)            if (b[e[i].x]!=b[e[i].y])            {                f[b[e[i].x]]++;                g[b[e[i].y]]++;            }        ans=0,ans2=0;        for (int i=1; i<=cnt; i++)///强连通分量        {            if (g[i]==0) ans++;            if (f[i]==0) ans2++;        }        if(n<1||cnt==1)///只有一个强连通分量,其本身就是强连通图咯        {            printf("0\n");            continue;        }        printf("%d\n",max(ans,ans2));    }    return 0;}

0 0
原创粉丝点击