Luogu4366[CodePlus#4] 最短路

原题链接:https://www.luogu.org/problemnew/show/P4366

最短路

题目背景

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

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

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

题目描述

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

对于任意的两座城市 i j ,企鹅们可以花费 ( i   x o r   j ) × C 的时间从城市 i 走到城市 j ,这里 C 为一个给定的常数。

当然除此之外还有 M 条单向的快捷通道,第 i 条快捷通道从第 F i ​​ 个城市通向第 T i ​​ 个城市,走这条通道需要消耗 V i ​​ 的时间。

现在来自 P enguin K ingdom U niversity 的企鹅豆豆正在考虑从城市 A 前往城市 B 最少需要多少时间?

输入输出格式
输入格式:

从标准输入读入数据。

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

接下来的 M 行,每行三个正整数 F i , T i , V i ( 1 F i N ) , 1 T i N , 1 V i 100 ) ,分别表示对应通道的起点城市标号、终点城市标号和通过这条通道需要消耗的时间。

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

输出格式:

输出到标准输出。

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

输入输出样例
输入样例#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

活泼可爱的出题人给大家留下了下面这张图。

Credit: https://www.luogu.org/discuss/show/38908

题解

凯老师洗澡时想出来的题。。。

暴力建图 O ( n 2 ) ,考虑如何优化建图:

点之间的编号变换可以看做二进制位上的逐步变换,所以我们将原来一条边从 i 练到 j 变成 i 分别向 2 0 , 2 1 , 2 2 , . . . 分别连边,这样每个点向外连 l o g 2 n 条边,就能表示所有转移,愉快 A C

代码
#include<bits/stdc++.h>
using namespace std;
const int M=3e5+5;
struct sd{int to,len;};
bool operator <(sd a,sd b){return a.len>b.len;}
int s,t,mx,n,m,k,dis[M];
vector<sd>mmp[M];
priority_queue<sd>dui;
void in()
{
    int a,b,c;
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=m;++i)scanf("%d%d%d",&a,&b,&c),mmp[a].push_back((sd){b,c});
    scanf("%d%d",&s,&t);
}
void build()
{
    for(mx=1;mx<n;mx<<=1);
    for(int i=1;i<=n;++i)for(int j=1;j<=mx;j<<=1)mmp[i].push_back((sd){i^j,j*k}),mmp[i^j].push_back((sd){i,j*k});
}
void dijkstra()
{
    memset(dis,63,sizeof(dis));dis[s]=0;
    dui.push((sd){s,0});sd f,t;
    while(!dui.empty())
    {
        f=dui.top();dui.pop();
        for(int i=mmp[f.to].size()-1;i>=0;--i)
        {
            t=mmp[f.to][i];
            if(dis[t.to]>dis[f.to]+t.len)dis[t.to]=dis[f.to]+t.len,dui.push((sd){t.to,dis[t.to]});
        }
    }
}
void ac(){build();dijkstra();printf("%d",dis[t]);}
int main(){in();ac();}

猜你喜欢

转载自blog.csdn.net/shadypi/article/details/81120155