题意:给出两个点所构成的一条边 点和边各有各的计数规则,已知所给的图是连通图,求能否从起点出发,每条边经过切只经过一次再次回到原点,若不能输出错误信息,若能输出可能存在的路径的最小字典序。
解题思路:
题目已经明确所给的图是连通图,所以不用在判断图的连通性了。先判断是否存在欧拉回路,若有度数为奇数的点则不存在。可以使用链式向前星存图,边的编号可以想象成类似于权值,要求输出的字典序最小,所以在dfs尝试回溯构建欧拉回路的时候,应该优先尝试权值小的点,所以要对读入的关系,先进行排序。最后判断就好了。
模板:
void dfs(int now)
{
for(int k = head[now] ; k != -1 ; k = edge[k].next)
{
if(!vis[k])
{
vis[k] = true;
vis[k^1] = true;
dfs(edge[k].to);
ans[iq++] = k;
}
}
}
比较悲哀的是,算法的思路很正确, 有一点细节没处理好, 导致WA了几次。
WA的dfs代码:警示自己
void dfs(int now)
{
for(int k = head[now] ; k != -1 ; k = edge[k].next)
{
if(!vis[k])
{
vis[k] = true;
vis[k^1] = true;
dfs(edge[k].to);
ans[iq++] = edge[k].way;
}
}
}
最后的AC代码
Memory: 840 KB | Time: 32 MS | |
Language: G++ | Result: Accepted |
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<cctype>
#include<list>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
using namespace std;
#define FOR(i, s, t) for(int i = (s) ; i <= (t) ; ++i)
#define REP(i, n) for(int i = 0 ; i < (n) ; ++i)
int buf[10];
inline long long read()
{
long long x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
inline void writenum(int i)
{
int p = 0;
if(i == 0) p++;
else while(i)
{
buf[p++] = i % 10;
i /= 10;
}
for(int j = p - 1 ; j >= 0 ; --j) putchar('0' + buf[j]);
}
/**************************************************************/
#define MAX_N 2005
const int INF = 0x3f3f3f3f;
bool vis[MAX_N];
int degree[MAX_N];
int cnt = 0;
int head[MAX_N];
struct node
{
int to, next, way;
} edge[MAX_N << 2];
struct node2
{
int u, v, w;
} a[MAX_N << 1];
int top = 0;
int iq = 0;
int ans[MAX_N];
inline void init()
{
memset(head, -1, sizeof(head));
memset(vis, false, sizeof(vis));
memset(degree, 0, sizeof(degree));
memset(ans, 0 ,sizeof(ans));
memset(a, 0, sizeof(a));
iq = 0;
top = 0;
cnt = 0;
}
void add_edge(int u, int v, int w)
{
edge[top].to = v;
edge[top].way = w;
edge[top].next = head[u];
head[u] = top++;
}
void dfs(int now)
{
for(int k = head[now] ; k != -1 ; k = edge[k].next)
{
int v = edge[k].to;
if(!vis[edge[k].way])
{
vis[edge[k].way] = true;
//vis[edge[k].way] = true;
dfs(v);
ans[iq++] = edge[k].way;
}
}
}
bool cmp(node2 a, node2 b)
{
return a.w < b.w;
}
int main()
{
int u, v, w;
while(scanf("%d%d", &u, &v)&&(u + v))
{
init();
// int cnt = 0;
// int tot = 0;
scanf("%d", &w);
a[cnt].u = u;
a[cnt].v = v;
a[cnt].w = w;
cnt++;
int home = min(u, v);
while(scanf("%d%d", &u, &v) && (u + v))
{
scanf("%d", &w);
a[cnt].u = u;
a[cnt].v = v;
a[cnt].w = w;
cnt++;
}
sort(a, a + cnt, cmp);
// for(int i = 0 ; i < cnt ; i++)
// {
// cout<<a[i].u<<" "<<a[i].v<<" "<<a[i].w<<endl;
// }
for(int i = 0 ; i < cnt ; i++)
{
add_edge(a[i].u, a[i].v, a[i].w);
add_edge(a[i].v, a[i].u, a[i].w);
degree[a[i].u]++;
degree[a[i].v]++;
}
int flag = 0;
for(int i = 0 ; i < 50 ; i++)
{
if(degree[i] % 2)
{
flag = 1;
break;
}
}
if(flag)
{
printf("Round trip does not exist.\n");
continue;
}
dfs(home);
for(int i = 0 ; i < iq ; i++)
{
cout<<ans[i]<<" ";
}
cout<<endl;
}
return 0;
}