题解:UVA302 John's trip
前置知识
你需要了解欧拉回路、基本图论、搜索,本题输入输出较为恶心,需要有良好的理解能力。
思路讲解
题意很清晰,很多朋友住在不同的街,约翰想走完每条街拜访每一位朋友,每条街只走一次,最后回到起点。
我们把街道看作双向边,给每条边加上编号,路口看作点,要求每条边只走一次且最后回到起点,显然是求出无向图的欧拉回路,知道是求欧拉回路,就很好分析了。
根据欧拉图的性质,每个节点度数一定为偶数,因此我们可以一边建图一边统计度数,接着遍历每个点,若度数不为
若该图存在欧拉回路,我们对每个点的边按照编号从小到大排序,实现字典序最小;然后从起点开始搜索,每次取出一条对应点未被标记的边,打上边标记,顺着边连的点继续搜索,搜索结束回溯时将边的编号加入答案栈里;所有搜索结束时,不断输出并弹出栈的栈顶元素,直到为空,这样就完成了求解任务。
代码展示
本题是欧拉回路模板题,但需要注意以下几点:
- 多测必须清空。
- 行末不允许多余空格。
- 每组数据输出的末尾应有两个换行。
- 记得给边按照编号大小排序,保证字典序。
- 是标记边,并非点。
下面是我的代码,仅供参考:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ld long double
#define endl '\n'
#define inf 0x3f3f3f3f
int x,y,z,s;
int du[107];
struct edge{
int to,id;
};
vector<edge> a[107];
bool vis[10007];
stack<int> st;
void dfs(int u){
for(auto i : a[u]){
int node=i.to,id=i.id;
if(vis[id]) continue;
vis[id]=1;
dfs(node);
st.push(id);
}
}
bool cmp(edge u,edge v){
return u.id<v.id;
}
int main(){
while(cin>>x>>y){
if(x==0&&y==0) return 0;
memset(vis,0,sizeof vis);
memset(a,0,sizeof a);
memset(du,0,sizeof du);
cin>>z;
s=min(x,y);
a[x].push_back({y,z});
a[y].push_back({x,z});
du[x]++,du[y]++;
while(cin>>x>>y){
if(x==0&&y==0) break;
cin>>z;
a[x].push_back({y,z});
a[y].push_back({x,z});
du[x]++,du[y]++;
}
bool f=0;
for(int i=1;i<=50;i++){
if(a[i].size()==0) continue;
sort(a[i].begin(),a[i].end(),cmp);
if(du[i]!=0&&du[i]%2==1){
f=1;
break;
}
}
if(f){
cout<<"Round trip does not exist.\n\n";
continue;
}
dfs(s);
while(!st.empty()){
cout<<st.top();
if(st.size()!=1) cout<<" ";
st.pop();
}
cout<<"\n\n";
}
return 0;
}