HDU

来源:互联网 发布:win8.1优化 编辑:程序博客网 时间:2024/06/13 05:28

HDU - 3594入口

题意:判断题目中给出的图是否符合,这图只有一个强连通分量 ,一条边只能出现在一个环里。

分析:判断只有一个连通分量用Tarjan算法就可以。关键是第二个。我们把对边的判断转化为对点的记录,在tarjan深搜的过程中,使用fa数组记录一下搜索的过程,即每个节点的父子关系,当我们发现一条回边的时候,我们从这个点使用fa向前追溯,追溯过程中建立一个数组记录每个节点的情况,只要这个点处于一个环里,就给它加1,如果这个点的值大于1,也就意味着有这个点同时属于两个环,同时意味着有一条边同时属于两个环。在判断一个点是否同时属于两个环的时候,环的汇聚点是不可以判断的!汇聚点完全可以属于两个环,但是却没有边同时属于两个环。所以汇聚点不加1.在追随过程中不要修改u和v的值,否则会出现强连通分量的判断错误。


#include<cstdio>#include<iostream>#include<cstring>#include<algorithm>#include<vector>#include<queue>using namespace std;const int INF=0x3f3f3f3f;const int N=50010;const int M=30100;bool insta[N];int head[N],dfn[N],low[N],sta[N],belong[N],du[N],fa[N],num[N];int nu,top,tot,sent,n,m,fans;struct edge{    int from,to,nex;}e[M];void add(int from,int to){    e[nu].from=from;    e[nu].to=to;    e[nu].nex=head[from];    head[from]=nu++;}void tarjan(int x){    low[x]=dfn[x]=++tot;    sta[top++]=x;    insta[x]=true;    for(int i=head[x];i!=-1;i=e[i].nex)    {        int y=e[i].to;        if(!dfn[y])        {            fa[y]=x;            tarjan(y);            low[x]=min(low[x],low[y]);        }        else if(insta[y])        {  if(dfn[y]<low[x])            low[x]=dfn[y];            int tem=x;            while(fa[tem]!=y)            {              num[tem]++;            if(num[tem]>1)            {                fans=false;                return;            }             tem=fa[tem];            }        }    }    if(low[x]==dfn[x])    {        int t;        sent++;        do        {            t=sta[--top];            insta[t]=false;            belong[t]=sent;        }while(t!=x);    }}void init(){    nu=1;    memset(head,-1,sizeof(head));    memset(dfn,0,sizeof(dfn));    memset(insta,false,sizeof(insta));    memset(du,0,sizeof(du));    memset(num,0,sizeof(num));}void solve(){   sent=top=tot=0;    for(int i=1;i<=n;i++)        if(!dfn[i])        tarjan(i);}int main(){    int TA,x,y;    scanf("%d",&TA);    while(TA--)    {        scanf("%d",&n);        init();        fans=true;        while(scanf("%d%d",&x,&y)!=EOF&&(x||y))        {            x++;            y++;            add(x,y);        }        solve();        if(sent==1&&fans)            printf("YES\n");        else            printf("NO\n");    }    return 0;}