一句话题意:
从一号点,可以回溯,但不能重新经过之前经过的节点
问走完所有点,最后走到n,走出的节点序的字典序最小是多少
由于图可能是一棵树或者一棵基环树,所以重点基本都在基环树上
NOIP的D2T1的原数据范围还是很小的,直接枚举环上断每一条边的最小答案即可
然而cz搞了一个数据加强版,显而易见就只能用(Theta(nlog n))的复杂度跑了
具体的方式是:走到环的入口的时候,判断一下节点大小关系,分情况讨论
这样可以避免很多无脑断边的情况
代码:
#include<bits/stdc++.h>
#define N 500005
using namespace std;
int n,m,u,v;
struct Edge
{
int next,to;
}edge[N<<1];
int cnt=0,head[N];
inline void add_edge(int from,int to)
{
edge[++cnt].next=head[from];
edge[cnt].to=to;
head[from]=cnt;
}
template<class T>inline void read(T &res)
{
char c;T flag=1;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
}
bool book[N],cir[N],hav;
int fa[N];
void dfs1(int u,int fa)
{
book[u]=1;
for(register int i=head[u];i;i=edge[i].next)
{
int v=edge[i].to;
if(v==fa) continue;
if(book[v])
{
hav=cir[u]=cir[v]=1;
return;
}
dfs1(v,u);
if(hav&&cir[v])
{
if(cir[u]) hav=0;
cir[u]=1;
return;
}
}
}
queue<int> ans;
void dfs2(int u,int pos)
{
if(book[u]) return;
book[u]=1;
ans.push(u);
priority_queue<int,vector<int>,greater<int> > qq;
for(register int i=head[u];i;i=edge[i].next)
{
int v=edge[i].to;
if(v==fa[u]) continue;
if(book[v]) continue;
qq.push(v);
}
while(!qq.empty())
{
int now=qq.top();
qq.pop();
if(!hav&&cir[now]&&now>pos&&qq.empty())
{
hav=1;
return;
}
int nxt=-0x3f3f3f3f;
if(!qq.empty()&&cir[u]) nxt=qq.top();
if(nxt==-0x3f3f3f3f) nxt=pos;
dfs2(now,nxt);
}
}
int main()
{
read(n);read(m);
for(register int i=1;i<=m;++i)
{
read(u);read(v);
add_edge(u,v);
add_edge(v,u);
}
dfs1(1,1);
memset(book,0,sizeof(book));
hav=0;
dfs2(1,0x3f3f3f3f);
while(!ans.empty())
{
printf("%d ",ans.front());
ans.pop();
}
return 0;
}
/*
6 6
1 2
2 3
2 4
2 5
3 6
4 6
*/
另外,这份代码好像有点问题,因为之前脑子一抽设的fa数组根本没更新
后面dfs2还用到了……
但是影响不大,还是可以A