西安电子科技大学第二届程序设计新生赛-F-zxy的长跑【欧拉回路】

题目链接


  好极了的欧拉回路,我们想知道怎样才能跑完所有的边,我们可以从度为奇数的点出发——因为这是欧拉回路的无向图的先觉调节,当然,这道题还有另外一种可能就是这是一个环,1->2, 2->3, 3->4, 4->1,那么就没有奇数度的点了,就是随便找一个id最小的点出发就是了。

  接下来讲解一下欧拉回路在本题中的思考,本题有坑点,但是放在后头说,我们首先得判断这群点是否在一棵树上,不然的话就跑不到所有的边,既然所有的边都要跑到,在存在奇数度的点的情况的时候,我们断不能从偶数度的点出发,先找到个id最小的奇数点,并从它出发,知道最终找到结束的节点,并且,结束的那个节点也断然是个奇数度的节点;另外,不存在奇数度的点情况呢,就是它们是一个完整的环,对于这样的情况,我们直接找到个最小id序的有度节点即可,当然强调有度的节点,不然会WA,因为题意没说节点从1开始(WA了好几发的亲身经历)。


#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxN = 505;
int N, M, du[maxN]={0}, path[maxN][maxN]={0}, root[maxN], rx, ry, st, ed, out_put[maxN], keys;
vector<int> vt[maxN];
struct Eddge
{
    int no, to;
    Eddge(int a=0, int b=0):no(a), to(b) {}
}edge[maxN<<1];
int fid(int x) { return x==root[x]?x:(root[x] = fid(root[x])); }
void init()
{
    for(int i=1; i<=N; i++) root[i] = i;
}
void dfs(int u)
{
    int len = (int)vt[u].size();
    for(int i=0; i<len; i++)
    {
        int v = vt[u][i];
        if(path[u][v])
        {
            path[u][v]--;
            path[v][u]--;
            dfs(v);
            out_put[++keys] = u;
        }
    }
}
int main()
{
    scanf("%d%d", &N, &M);
    init();
    for(int i=1; i<=M; i++)
    {
        scanf("%d%d", &edge[i].no, &edge[i].to);
        path[edge[i].no][edge[i].to]++;
        path[edge[i].to][edge[i].no]++;
        vt[edge[i].to].push_back(edge[i].no);
        vt[edge[i].no].push_back(edge[i].to);
        du[edge[i].no]++;
        du[edge[i].to]++;
        rx = fid(edge[i].no);   ry = fid(edge[i].to);
        if(rx != ry) root[rx] = ry;
    }
    for(int i=1; i<=N; i++) sort(vt[i].begin(), vt[i].end());
    int num = 0, the_tree = 0;
    for(int i=1; i<=N; i++)
    {
        if(du[i] & 1) num++;
        if(root[i] == i && du[i]) the_tree++;
    }
    if(num > 2 || the_tree>1) { printf("-1\n"); return 0; }
    st = ed = 1;
    for(int i=1; i<=N; i++)
    {
        if(du[i]) { st = ed = i; break; }   //题中没说节点从1开始
    }
    if(num == 2)
    {
        for(int i=1; i<=N; i++)
        {
            if(du[i] & 1)
            {
                st = ed = i;
                break;
            }
        }
        for(int i=N; i>=1; i--)
        {
            if(du[i] & 1)
            {
                ed = i;
                break;
            }
        }
    }
    dfs(st);
    for(int i=keys; i>=1; i--) printf("%d ", out_put[i]);
    printf("%d\n", ed);
    return 0;
}

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wuliwuliii

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值