hdu 5883 The Best Path-ICPC网络赛青岛赛区

探讨一笔画问题中寻找经过每条边恰好一次的路径,并最大化路径上节点值的异或结果。介绍如何判断图的欧拉路径特性,通过算法实现及代码示例。

The Best Path

Problem Description

Alice is planning her travel route in a beautiful valley. In this valley, there are N lakes, and M rivers linking these lakes. Alice wants to start her trip from one lake, and enjoys the landscape by boat. That means she need to set up a path which go through every river exactly once. In addition, Alice has a specific number (a1,a2,...,an) for each lake. If the path she finds is P0P1...Pt, the lucky number of this trip would be aP0XORaP1XOR...XORaPt. She want to make this number as large as possible. Can you help her?

 


Input

The first line of input contains an integer t, the number of test cases. t test cases follow.

For each test case, in the first line there are two positive integers N (N100000) and M (M500000), as described above. The i-th line of the next N lines contains an integer ai(i,0ai10000) representing the number of the i-th lake.

The i-th line of the next M lines contains two integers ui and vi representing the i-th river between the ui-th lake and vi-th lake. It is possible that ui=vi.

 


Output

For each test cases, output the largest lucky number. If it dose not have any path, output "Impossible".

 


Sample Input

2 3 2 3 4 5 1 2 2 3 4 3 1 2 3 4 1 2 2 3 2 4

 


Sample Output

2 Impossible

 

题意

p个点q个边,要求遍历每个边且仅经过一次,如果不能则输出impossible 如果能,那么没经过一个点,就要异或这个点的值,问最大结果是多少


解题思路

这是一笔画问题,也就是欧拉回路或通路问题。

判断一个图是否是欧拉回路或通路 有两步

1、是通路

2、欧拉回路没有奇度点,欧拉通路有且仅有2个奇度点

题目没卡数据,不需要判断是不是通路也能过。。。。

如果要判断图是否连通就比较麻烦了,因为,如果有孤立点(无边)应该算合法

由欧拉路性质,奇度点数量为0或2。一个节点被进一次出一次,度减2,产生一次贡献,因此节点u的贡献为 val[i] * ((degree[i]/2)%2),

***degree[i]/2表示经过这个点几次,奇数次相当于经过一次,只异或一次就行,偶数次相当于没异或,等价于异或0***

欧拉回路的起点贡献多一次,欧拉通路的起点和终点贡献也多一次。因此如果是欧拉回路的话枚举一下起点,欧拉通路处理两个奇度点就好了。


代码(没判断图是否通路)

#include<cstdio>
#include<iostream>
#include<cstring>
const int maxs=100010;
using namespace std;
int p,q,degree[maxs],val[maxs],ans;

void mxor()//解决欧拉通路和不进行起点多加1的异或
{
    ans=0;
    for(int i=1;i<=p;++i)
        if(degree[i]>0)
            ans^=val[i];
}

int main()
{
    int t,i,j,b,c,f,odd[3];
    scanf("%d",&t);
    while(t--)
    {
        j=f=0;
        memset(degree,0,sizeof(degree));
        memset(odd,-1,sizeof(odd));

        //处理输入
        scanf("%d%d",&p,&q);
        for(i=1; i<=p; ++i)
            scanf("%d",&val[i]);
        while(q > 0)
        {
            q--;
            scanf("%d%d",&b,&c);
            degree[b]++;
            degree[c]++;
        }

        //判断奇度点个数
        for(i=1; i<=p; i++)
        {
            if(degree[i] & 1)//统计奇度点的个数
            {
                odd[j]=i;
                j++;
                if (j > 2)
                {
                    break;
                }
            }
            //如果是奇度点,贡献度要多加一
            if(odd[0]==i||odd[1]==i)
                val[i]*=(degree[i]/2+1)%2;

            else val[i]*=(degree[i]/2)%2;
        }

        if(j==0||j==2)
            f=1;
        else
            f=0;

        //处理输出
        if(f==0)printf("Impossible\n");
        else
        {
            if(j==2)//欧拉通路
            {
                mxor();
                printf("%d\n",ans);
            }
            else if(j==0)//欧拉回路
            {
                int maxn=-1;
                mxor();
                for(i=1;i<=p;++i)//枚举回路起点
                {
                    int now=0;
                    now=val[i]^ans;//多异或一次起点
                    if(now>maxn)
                        maxn=now;
                }
                printf("%d\n",maxn);
            }
        }
    }
    return 0;
}

代码 (判断图是否连通)


#include<cstdio>
#include<iostream>
#include<cstring>
const int maxs=100010;
using namespace std;
int a[maxs],p,q,degree[maxs],val[maxs],ans;

int Find(int x)
{
    int tmp = x;
    while (a[tmp] != tmp)
    {
        tmp = a[tmp];
    }
    int now=x,New;//w表示当前结点,new表示当前结点的父亲节点
    while(a[now]!=tmp)
    {
        New=a[now];
        a[now]=tmp;
        now=New;
    }
    return tmp;
}

void mxor()//解决欧拉通路和不进行起点多加1的异或
{
    ans=0;
    for(int i=1;i<=p;++i)
        if(degree[i]>0)
            ans^=val[i];
}

int main()
{
    int t,i,j,b,c,f,odd[3];
    scanf("%d",&t);
    while(t--)
    {
        j=f=0;
        memset(a,0,sizeof(a));
        memset(degree,0,sizeof(degree));
        memset(val,0,sizeof(val));
        memset(odd,-1,sizeof(odd));

        scanf("%d%d",&p,&q);

        for(i=1; i<=p; i++)
        {
            a[i]=i;
        }

        for(i=1; i<=p; ++i)
            scanf("%d",&val[i]);

        while(q > 0)
        {
            q--;
            scanf("%d%d",&b,&c);
            degree[b]++;
            degree[c]++;
            int x = Find(b);
            int y = Find(c);
            if (x != y)
                a[x] = y;
        }
        for(i=1; i<=p; i++)
        {
            //判断是否通路
            if(a[i]==i&& degree[i]>0)
            {
                k++;
                if(k>1) {f=0;break;}
            }

            if(degree[i] & 1)//统计奇度点的个数
            {
                odd[j]=i;
                j++;
                if (j > 2)
                    break;
            }
            if(odd[0]==i||odd[1]==i)
                val[i]*=((degree[i]/2+1)%2);
            else val[i]*=(degree[i]/2)%2;
        }

        if(j==0||j==2)
            f=1;
        else
            f=0;

        if(f==0)printf("Impossible\n");
        else if(j==2)//欧拉通路
        {
            mxor();
            printf("%d\n",ans);
        }
        else if(f&&j==0)//欧拉回路
        {
            int maxn=-1;
            mxor();
            for(i=1;i<=p;++i)//枚举回路起点
            {
                int now=0;
                now=val[i]^ans;//多异或一次起点

                if(now>maxn)
                    maxn=now;
            }
            printf("%d\n",maxn);
        }

    }

    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值