原题链接:https://www.luogu.org/problemnew/show/P4366
最短路
题目背景
在北纬 91° ,有一个神奇的国度,叫做企鹅国。这里的企鹅也有自己发达的文明,称为企鹅文明。因为企鹅只有黑白两种颜色,所以他们的数学也是以二进制为基础发展的。
比如早在 11101001 11101001 年前,他们就有了异或这样一个数学概念。如果你不知道异或是什么,请出门过墙左转到这里。
再比如早在 1000010 1000010 年前,他们的大科学家 Penguin. Tu 就提出了图和最短路径这样一些概念。
题目描述
企鹅国中有 N N 座城市,编号从 到 N N 。
对于任意的两座城市 和 j j ,企鹅们可以花费 的时间从城市 i i 走到城市 ,这里 C C 为一个给定的常数。
当然除此之外还有 条单向的快捷通道,第 i i 条快捷通道从第 个城市通向第 Ti T i 个城市,走这条通道需要消耗 Vi V i 的时间。
现在来自 P enguin K ingdom U niversity 的企鹅豆豆正在考虑从城市 A A 前往城市 最少需要多少时间?
输入输出格式
输入格式:
从标准输入读入数据。
输入第一行包含三个整数 N,M,C N , M , C ,表示企鹅国城市的个数、快捷通道的个数以及题面中提到的给定的常数 C C 。
接下来的 行,每行三个正整数 Fi,Ti,Vi(1≤Fi≤N),1≤Ti≤N,1≤Vi≤100) F i , T i , V i ( 1 ≤ F i ≤ N ) , 1 ≤ T i ≤ N , 1 ≤ V i ≤ 100 ) ,分别表示对应通道的起点城市标号、终点城市标号和通过这条通道需要消耗的时间。
最后一行两个正整数 A,B(1≤C≤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 1 走到 就好了。
样例2解释
先从 3 3 走到 ,再从 2 2 通过通道到达 ,再从 4 4 走到 。
活泼可爱的出题人给大家留下了下面这张图。
Credit: https://www.luogu.org/discuss/show/38908
题解
凯老师洗澡时想出来的题。。。
暴力建图 O(n2) O ( n 2 ) ,考虑如何优化建图:
点之间的编号变换可以看做二进制位上的逐步变换,所以我们将原来一条边从 i i 练到变成 i i 分别向分别连边,这样每个点向外连 log2n l o g 2 n 条边,就能表示所有转移,愉快 AC 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();}