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;
}