标签:int 路径 ++ P7711 maxn cnt2 cnt1 欧拉 Out
看到题解没有,来一发空间、时间均为 \(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)\) 快……
不过也没事。毕竟,普通平衡树和其加强版的最优解不是平衡树,线性筛素数的最优解不是欧氏筛……
标签:int,路径,++,P7711,maxn,cnt2,cnt1,欧拉,Out 来源: https://www.cnblogs.com/kkksc0100/p/euler-road.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。