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\n",ans[i]);
	return 0;
}
posted @   Seaway-Fu  阅读(102)  评论(0编辑  收藏  举报
编辑推荐:
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示