Codeforces 845G Shortest Path Problem?(异或最短路)

87 篇文章 0 订阅
21 篇文章 0 订阅

G. Shortest Path Problem?
time limit per test
3 seconds
memory limit per test
512 megabytes
input
standard input
output
standard output

You are given an undirected graph with weighted edges. The length of some path between two vertices is the bitwise xor of weights of all edges belonging to this path (if some edge is traversed more than once, then it is included in bitwise xor the same number of times). You have to find the minimum length of path between vertex 1 and vertex n.

Note that graph can contain multiple edges and loops. It is guaranteed that the graph is connected.

Input

The first line contains two numbers n and m (1 ≤ n ≤ 100000n - 1 ≤ m ≤ 100000) — the number of vertices and the number of edges, respectively.

Then m lines follow, each line containing three integer numbers xy and w (1 ≤ x, y ≤ n0 ≤ w ≤ 108). These numbers denote an edge that connects vertices x and y and has weight w.

Output

Print one number — the minimum length of path between vertices 1 and n.

Examples
input
3 3
1 2 3
1 3 2
3 2 0
output
2
input
2 2
1 1 3
1 2 3
output
0


题目大意:

    给你一个无向带权图,定义最短路为一条路径上各条边的权值异或,求从点1到点N的最短路径。


解题思路:

    首先可以发现对于图上的路径异或,环非常特殊。因为无向图任意一条路径走过去再原路走回来不会造成任何花费,我们可以把环的花费异或到任意一条路径上而不需要额外的花费。而且我们可以通过向一条路径添加和路径有重复边的环来改变路径。

    所以我们可以先随意建立一棵生成树,同时得到一条1到N的路径,非生成树上的边可以构成环,由于环非常多而且我们通过这个方式也没有得到的并不是环,只是所有环都可以有它们得到。所以需要利用高斯消元得到线性无关的向量组即可,然后保存下来。最终枚举把这些向量加到初始路径上的情况,得到的最小值即为答案。

    感觉好像还是讲得不是很清楚-_-,附上官方题解:



AC代码:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <string>
#include <ctime>
using namespace std;
#define INF 0x3f3f3f3f
#define ULL unsigned long long
#define LL long long
#define fi first
#define se second
#define P pair<int,bool>

const int MAXV=100000+3;
int V, E;
vector<pair<int, int>> G[MAXV];//图的邻接表表示:to, cost
vector<int> circle;//保存环的花费高斯消元后的线性无关向量组
int dist[MAXV];//生成树上从根节点到当前结点花费
bool vis[MAXV];

void add(int x)//添加环,并且使每个环的二进制表示线性无关
{
    for(int i=0;i<circle.size();++i)
        x=min(x, x^circle[i]);
    if(x)
        circle.push_back(x);
}

void dfs(int u)//随意建立一棵生成树,然后找到环
{
    vis[u]=true;
    for(int i=0;i<G[u].size();++i)
    {
        int v=G[u][i].fi;
        if(!vis[v])
        {
            dist[v]=dist[u]^G[u][i].se;
            dfs(v);
        }
        else add(dist[v]^G[u][i].se^dist[u]);
    }
}

int main()
{
    scanf("%d%d", &V, &E);
    for(int i=0;i<E;++i)
    {
        int u, v, c;
        scanf("%d%d%d", &u, &v, &c);
        G[u].push_back(make_pair(v, c));
        G[v].push_back(make_pair(u, c));
    }
    dfs(1);
    for(int i=0;i<circle.size();++i)//高斯消元,使路径花费最小
        dist[V]=min(dist[V], dist[V]^circle[i]);
    printf("%d\n", dist[V]);
    
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值