zoukankan      html  css  js  c++  java
  • POI 2008 CLO-Toll

    POI 2008 CLO-Toll

    洛谷传送门

    题意翻译

    题目描述:

    给你 nn 个点和 mm 条双向边,问能否将其中的一些边改成有向边,使得只考虑有向边的情况下每个点的入度都为 11 。

    输入格式:

    第一行输入 n,m(1≤n≤100000,1≤m≤200000)n,m(1≤n≤100000,1≤m≤200000) ,接下来 mm 行每行两个数 a,ba,b 表示点 aa 和点 bb 之间有一条双向边。输入保证没有重边与自环。

    输出格式:

    若没有合法方案,输出 NIENIE ,否则先在第一行输出 TAKTAK ,然后在第 i+1i+1 行输出点 ii 的入度是由哪个点出发的边所得到的。

    感谢@hdxrie 提供的翻译


    题解:

    其实很简单的。就是在每个连通块里拎出来基环树。

    如果拎不出连通块,那就是NIE。

    然后考虑怎么拎基环树。

    基环树是啥啊,就是一棵树加上任意一条边呗。这条边就是“返祖边”啊。所以我们只需要对每个连通块DFS一遍,只拎一条返祖边(这个用flag维护),碰到返祖边,就说明可以和一些节点构成一个环,这样的话就回溯,把所有沿途节点全部反向即可。

    代码:

    #include<cstdio>
    using namespace std;
    const int maxn=1e5+5;
    const int maxm=2e5+5;
    int n,m;
    int tot,head[maxn],nxt[maxm<<1],to[maxm<<1];
    int fa[maxn],ans[maxn];
    bool v[maxn];
    bool flag;
    void add(int x,int y)
    {
    	to[++tot]=y;
    	nxt[tot]=head[x];
    	head[x]=tot;
    }
    void dfsback(int x,int s)
    {
    	if(ans[x])
    		dfsback(ans[x],x);
    	ans[x]=s;
    }
    void dfs(int x)
    {
    	v[x]=1;
    	for(int i=head[x];i;i=nxt[i])
    	{
    		int y=to[i];
    		if(y==fa[x])
    			continue;
    		if(v[y])
    		{
    			if(!flag)
    			{
    				flag=1;
    				dfsback(y,x);
    			}
    		}
    		else
    		{
    			ans[y]=fa[y]=x;
    			dfs(y);
    		}
    	}
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=m;i++)
    	{
    		int x,y;
    		scanf("%d%d",&x,&y);
    		add(x,y);
    		add(y,x);
    	}
    	for(int i=1;i<=n;i++)
    		if(!v[i])
    		{
    			flag=0;
    			dfs(i);
    			if(!flag)
    			{
    				puts("NIE");
    				return 0;
    			}
    		}
    	puts("TAK");
    	for(int i=1;i<=n;i++)
    		printf("%d
    ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    12月10日,小雪
    12月10日,小雪
    BUG
    Twenty Hours
    BUG
    07中华小姐大赛落幕 20岁佳丽曾光夺冠
    Twenty Hours
    jeecg 页面标签规则
    jeecg导入备份
    jeecg查询分页
  • 原文地址:https://www.cnblogs.com/fusiwei/p/14084163.html
Copyright © 2011-2022 走看看