标签:continue add 物流业务 小明 模板题 code 节点 iostream size
题目大意:
为了增加公司收入,F公司新开设了物流业务。由于F公司在业界的良好口碑,物流业务一开通即受到了消费者的欢迎,物流业务马上遍及了城市的每条街道。然而,F公司现在只安排了小明一个人负责所有街道的服务。
任务虽然繁重,但是小明有足够的信心,他拿到了城市的地图,准备研究最好的方案。城市中有n个交叉路口,m条街道连接在这些交叉路口之间,每条街道的首尾都正好连接着一个交叉路口。除开街道的首尾端点,街道不会在其他位置与其他街道相交。每个交叉路口都至少连接着一条街道,有的交叉路口可能只连接着一条或两条街道。
小明希望设计一个方案,从编号为1的交叉路口出发,每次必须沿街道去往街道另一端的路口,再从新的路口出发去往下一个路口,直到所有的街道都经过了正好一次。
看到这个题就是一个一笔画的题,简单来说就是欧拉通路的模板题,欧拉通路可以用Hierholzer算法来做,大概思路就是递归去走一条路,然后删掉当前走过的边,直到走完所有的路。
本题要求字典序最小,那么就要每次扩展的时候选择最小结点号扩展就行了。
无向图:
1、存在欧拉回路的条件:原图连通,每个节点均为偶度节点。
2、存在欧拉通路的条件:存在欧拉回路,或原图连通,有两个节点为奇度节点,其他节点均为偶度节点,而且出发顶点一定是奇数结点。
有向图:
1、存在欧拉回路的条件:基图(有向边变成无向边)连通,每个节点的入度等于出度。
2、存在欧拉通路的条件:存在欧拉回路,或基图连通,有一个节点入度等于出度+1,有一个节点出度等于入度+1,其他节点入度等于出度,出发点的出度大于入度。
代码:
#include <iostream> #include <algorithm> #include <stack> #include <cstring> using namespace std; //欧拉通路 const int N =1e5+10; const int M =2e5+10; int h[N],ne[M],to[M],idx=0; void add(int a,int b){ int last=-1; for(int i=h[a];~i;i=ne[i]){ int v=to[i]; if(b<v){ if(last==-1){ ne[idx]=h[a]; to[idx]=b; h[a]=idx++; } else{ ne[idx]=i; to[idx]=b; ne[last]=idx++; } return ; } last=i; } if(last==-1){ ne[idx]=h[a]; to[idx]=b; h[a]=idx++; return ; } ne[idx]=-1; to[idx]=b; ne[last]=idx++; } int d[N],vi[N],vii[M]; int cnt=0; int main(){ int n,m; scanf("%d%d",&n,&m); memset(h,-1,sizeof h); for(int i=0;i<m;i++){ int a,b; scanf("%d%d",&a,&b); add(a,b); add(b,a); d[a]++; d[b]++; } int odd=0; for(int i=1;i<=n;i++){ if(d[i]&1)odd++; } stack<int> st1,st2; st1.push(1); while(st1.size()){ int t=st1.top(); int minj=h[t]; if(minj==-1){ st2.push(t); st1.pop(); } else { if(vii[h[t]]){ h[t]=ne[h[t]]; continue; } int minid=to[h[t]]; h[t]=ne[h[t]]; vii[minj]=1; vii[minj^1]=1; st1.push(minid); } } if(st2.size()==m+1&&(odd==0||(odd==2&&d[1]%2))){ while(st2.size()){ printf("%d ",st2.top()); st2.pop(); } cout<<endl; } else puts("-1"); }
标签:continue add 物流业务 小明 模板题 code 节点 iostream size
原文地址:https://www.cnblogs.com/kstranger/p/13547005.html