BZOJ1116: [POI2008]CLO

【传送门:BZOJ1116


简要题意:

  给出n个点,m条无向边,判断是否能够通过将某些边变成单向边,使得每个点入度都为1


题解:

  因为每个点入度都为1时,必定是一棵外向树,而外向树有且仅有一个环

  那么就判断所有连通图是否满足有且只有一个简单环,用tarjan来判


参考代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
struct node
{
    int x,y,next;
}a[410000];int len,last[110000];
void ins(int x,int y)
{
    len++;
    a[len].x=x;a[len].y=y;
    a[len].next=last[x];last[x]=len;
}
bool v[110000];
int dfn[110000],low[110000],id;
int sta[110000],tp;
int cnt;
void tj(int x,int fa)
{
    dfn[x]=low[x]=++id;
    sta[++tp]=x;v[x]=true;
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(y==fa) continue;
        if(dfn[y]==0)
        {
            tj(y,x);
            low[x]=min(low[x],low[y]);
        }
        else if(v[y]==true) low[x]=min(low[x],dfn[y]);
    }
    if(low[x]==dfn[x])
    {
        int i,sum=0;
        do
        {
            i=sta[tp--];
            v[i]=false;sum++;
        }while(i!=x);
        if(sum>=3) cnt++;
    }
}
int main()
{int n,m;
    scanf("%d%d",&n,&m);
    len=0;memset(last,0,sizeof(last));
    for(int i=1;i<=m;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        ins(x,y);ins(y,x);
    }
    memset(v,false,sizeof(v));
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    id=tp=cnt=0;
    for(int i=1;i<=n;i++)
    {
        if(dfn[i]==0)
        {
            tj(i,0);
            if(cnt!=1)
            {
                printf("NIE\n");
                return 0;
            }
            cnt=0;
        }
    }
    printf("TAK\n");
    return 0;
}
posted @ 2018-09-30 10:56  Star_Feel  阅读(120)  评论(0编辑  收藏  举报