欧拉路径/P7711【模板】欧拉路径

看到题解没有,来一发空间、时间均为 \(O(n+m)\) 的做法。

请使用 vector 存图。链式前向星爬

明显有两个结论:

存在欧拉路径的充要条件是:

1.该有向图的基图联通。(已保证)

2.各有 \(1\) 或 \(0\) 个出度 \(-\) 入度、入度 \(-\) 出度 \(=1\) 的点。

先用这个判 No

字典序最小,对于每一个点连出的边按另一个端点排序即可。

dfs 解决。得用个当前弧。

排序优化。

\(O(n)\) 的排序:计数、桶、基数。

wtcl,我只会桶。当然你要基数也是珂以的。

但是每个点都扫描一次桶,TLE 等着你。

一次性把所有点存进去。不能像一般的那样 \(+1\),要存入他的编号。

一个桶需要开 vector。总共只会有 \(m\) 个存入,不会 MLE

具体见代码。

这个空间、时间均为下限。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
vector<int> e[maxn],t[maxn];
stack<int> st;
int In[maxn],Out[maxn],cur[maxn];
int n,m,cnt1=0,cnt2=0; 
void rt(){
	cout<<"No"<<endl;
	exit(1);
    /*
    想学习题解的同学,请把这里改成 0。否则 RE 。
    */
}
void dfs(int u){
   for(int i=cur[u];i<e[u].size();i=cur[u]){ //当前弧
       cur[u]=i+1;
       dfs(e[u][i]); 
   }
   st.push(u); 
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		int u,v;
		cin>>u>>v;
		In[v]++,Out[u]++;
		t[v].push_back(u);
	}
	int cnt1=0,cnt2=0,pd=0,start=1;
	for(int i=1;i<=n;i++){
	   if(Out[i]!=In[i])pd=1;
		if(Out[i]-In[i]>1)rt();//因为可以认为有一个出边永远不可能被遍历到
		if(Out[i]-In[i]==1)start=i,cnt1++;
		if(In[i]-Out[i]==1)cnt2++;
	}
    if(!(pd==0||((cnt1==cnt2)&&cnt1==1)))rt();
	for(int i=1;i<=n;i++){
		for(auto x:t[i])e[x].push_back(i);
	}
	memset(cur,0,sizeof(cur));
	dfs(start);
	while(!st.empty()){
		cout<<st.top()<<" ";
		st.pop(); 
	}
	return 0;
}

附:写的时候的奇怪的事情

我因为 dfs 初始参数写成 \(1\) 交了很多遍。

最优解那个真的玄学。为什么我的卡过的 \(O(n+m)\) 没有卡过的 \(O(n+m\log m)\) 快……

不过也没事。毕竟,普通平衡树和其加强版的最优解不是平衡树,线性筛素数的最优解不是欧氏筛……

上一篇:【外文翻译】使用Timer类去调度任务 ——java


下一篇:《Codeforces Round #732 (Div. 1)》