[Code+#4]最短路 (最短路)

[Code+#4]最短路

题目背景

在北纬 91° ,有一个神奇的国度,叫做企鹅国。这里的企鹅也有自己发达的文明,称为企鹅文明。因为企鹅只有黑白两种颜色,所以他们的数学也是以二进制为基础发展的。

比如早在 1110100111101001 年前,他们就有了异或这样一个数学概念。如果你不知道异或是什么,请出门过墙左转到这里

再比如早在 10000101000010 年前,他们的大科学家 Penguin. Tu 就提出了最短路径这样一些概念。

题目描述

企鹅国中有 N 座城市,编号从 1 到 N 。

对于任意的两座城市 i 和 j ,企鹅们可以花费 \((i~\mathrm{xor}~j) \times C\) 的时间从城市 i 走到城市 j ,这里 C 为一个给定的常数。

当然除此之外还有 \(M\) 条单向的快捷通道,第 \(i\) 条快捷通道从第 \(F_i\) 个城市通向第 \(T_i\)​​​ 个城市,走这条通道需要消耗 \(V_i\)​​​ 的时间。

现在来自 Penguin Kingdom University 的企鹅豆豆正在考虑从城市 A 前往城市 B 最少需要多少时间?

输入输出格式

输入格式:

从标准输入读入数据。

输入第一行包含三个整数 \(N,M,C\) ,表示企鹅国城市的个数、快捷通道的个数以及题面中提到的给定的常数CC。

接下来的 M 行,每行三个正整数 \(F_i,T_i,V_i (1≤Fi​≤N,1 \leq T_i \leq N ,1\leq V_i \leq 100)\),分别表示对应通道的起点城市标号、终点城市标号和通过这条通道需要消耗的时间。

最后一行两个正整数 A,B \((1 \leq C \leq 100)\),表示企鹅豆豆选择的起点城市标号和终点城市标号。

输出格式:

输出到标准输出。

输出一行一个整数,表示从城市 A 前往城市 B 需要的最少时间。

输入输出样例

输入样例#1: 复制

4 2 1
1 3 1
2 4 4
1 4

输出样例#1: 复制

5

输入样例#2: 复制

7 2 10
1 3 1
2 4 4
3 6

输出样例#2: 复制

34

说明

样例1解释

直接从 1 走到 4 就好了。

样例2解释

先从 3 走到 2 ,再从 2 通过通道到达 4 ,再从 4 走到 6。

0

题解

一道思路非常巧妙的题目。
在这里我们要充分利用到异或的性质。
我们知道如果 A^ B ^ C ^ D =A^E时。
就直接建边A->E了。
也就是说,有些边是多余的。
那么我们怎么确保必要的边呢?
一个点到只需要连接n的每一个二进制的1就可以了。
因为所有的异或情况都可以由二进制组合出来。
那么边就是\(m+log(n)\)的。

代码

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
const int N=4000001;
struct node{
    int to,v,nex;
}e[N];
int num,head[N];
int n,m,c,s,t,dis[N],vis[N];
int read(){

    int x=0,w=1;char ch=getchar();
    while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*w;
}

void add(int from,int to,int v){
    num++;
    e[num].to=to;
    e[num].v=v;
    e[num].nex=head[from];
    head[from]=num;
}

void dijkstra(){
    priority_queue<pair<int,int> >q;
    memset(dis,63,sizeof(dis));dis[s]=0;
    q.push(make_pair(-dis[s],s));
    while(!q.empty()){
        int u=q.top().second;q.pop();
        if(vis[u])continue;vis[u]=1;
        for(int i=head[u];i;i=e[i].nex){
            int v=e[i].to;
            if(dis[v]>dis[u]+e[i].v){
                dis[v]=dis[u]+e[i].v;
                q.push(make_pair(-dis[v],v));
            }
        }
    }
}

int main(){
    n=read();m=read();c=read();
    for(int i=1;i<=m;i++){
        int x=read(),y=read(),z=read();
        add(x,y,z);
    }
    for(int i=0;i<=n;i++){
        for(int j=1;j<=n;j<<=1){
            if((j^i)>n)continue;
            add(i,(i^j),j*c);
        }
    }
    s=read();t=read();
    dijkstra();
    printf("%d\n",dis[t]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/hhh1109/p/9588741.html