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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 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 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架