HDU-5883-The Best Path

168 篇文章 0 订阅
14 篇文章 0 订阅

ACM模版

描述

描述

题解

给定一个无向图,关于欧拉路的问题。这里我们要求的是这个路径的结点异或在一起的最大值。

首先,我们可以通过判断度的奇偶性来判断是否是 Impossible ,因为欧拉路径存在两种,一种是欧拉通路,一种是欧拉回路。通路是起点、终点是不同点,那么我们需要将起点终点多算一次,并且起点和终点是固定的,必然是度为奇数的结点,那么我们也就知道了这种情况需要度为奇数的结点只有连个;回路呢,其实是起点、终点重合,变成了同一个点,所以呢,我们需要对这个起点多算一次即可了,但是这里起点不唯一,所以需要枚举起点。

那么问题来了,每个结点的异或次数是多少呢?实际上这个和度有关,因为我们可以想象的到的是,每次经过一个结点,除了起点和终点外,必然是一个入度和一个出度,想要让每条路都走一遍,需要把这些度都消费掉,那么每个结点的异或次数自然就是度数的一半了,然而这里还要一个小小的优化就是,异或不管次数再多,只有两种结果,一种是异或奇数次,一种是异或偶数次,因为偶数次的异或会抵消异或的效力,酱紫就好做很多了。这里需要注意的是,起点和终点多算一次异或也就行了。

所以呢,这里的第一个过程不考虑起点时,求得一个异或值后,接着在第二个过程加入起点和终点,如果是通路,就是固定起点和终点,比较容易解决,回路就需要遍历求最大值,而这里我们需要注意的是,插入起点后,结果可能比第一个过程的临时结果大,也可能小,所以需要格外注意取最的过程,不要以为只会变大哦~~~

对了,网上看到了一种别人的 AC 代码,十分的古怪,经过仔细的研究,发现他的代码可能是因为测试数据比较弱导致 AC 的,测试数据应该叫上一组酱紫的:

1
6 10
1 2 4 8 16 32
1 6
1 5
1 4
1 2
2 5
2 4
2 3
3 4
4 5
5 6
//  ans = 52

而他的代码结果竟然为 63 ,明显是重复计算了起点,他的代码问题出在了回路枚举起点的过程,脑洞回路有些怪,所以写了那么个稀奇的代码,让我推敲了好大会儿, hack 了一组数据搞搞事情~~~额,说起来 hack 这个词,我也是刚刚才知道是什么意思的。具体是哪个朋友的题解我就不说了,如果看到了那个错的 AC 代码,您可以看到我在评论区的一番疑问……O(∩_∩)O哈哈~

这是我第一次做欧拉路的问题,感觉花费了好几个小时是值得的,让我更深入的理解了欧拉路的存在。

代码

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

const int MAXN = 1e5 + 7;

int n, m;
int a[MAXN];
int degree[MAXN];

int main()
{
    int T;
    scanf("%d", &T);

    while (T--)
    {
        memset(degree, 0, sizeof(degree));

        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++)
        {
            scanf("%d", &a[i]);
        }

        int u, v;
        for (int i = 1; i <= m; i++)
        {
            scanf("%d%d", &u, &v);
            degree[u]++;
            degree[v]++;
        }

        int cnt = 0;
        for (int i = 1; i <= n; i++)
        {
            if (degree[i] & 1)
            {
                cnt++;
            }
        }
        if (cnt != 0 && cnt != 2)
        {
            printf("Impossible\n");
            continue;
        }

        int ans = 0;
        for (int i = 1; i <= n; i++)
        {
            degree[i] = (degree[i] + 1) >> 1;
            if (degree[i] & 1)
            {
                ans ^= a[i];
            }
        }
        int tmp = 0;
        if (cnt == 0)
        {
            for (int i = 1; i <= n; i++)
            {
                tmp = max(tmp, ans ^ a[i]);
            }
            ans = tmp;
        }

        printf("%d\n", ans);
    }

    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值