zoukankan      html  css  js  c++  java
  • [洛谷P4366] 最短路

    问题背景

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

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

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

    问题描述

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

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

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

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

    输入格式

    从标准输入读入数据。

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

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

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

    输出格式

    输出到标准输出。

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

    样例输入

    4 2 1
    1 3 1
    2 4 4
    1 4

    样例输出

    5

    解析

    直观的一个思路是把所有题目中涉及的边(包括两两之间的路线)连起来,然后跑最短路。但是这样边的数量是(N^2)级别的。我们需要考虑优化连边。

    观察第二种边的性质。第二种边是由异或定义的,不妨考虑拆位,异或运算就是对于每一个二进制位来决定的。那么,对于一个运算(a xor b),其等价于

    [a xor b=a xor 2^{k_1} xor 2^{k_2} xor ... xor 2^{k_m} ]

    那么,由异或运算的性质,图上从(a)走到(b),相当于从(a)走到(a xor 2^{k_1}),再从(a xor 2^{k_1})走到(a xor 2^{k_1} xor 2^{k_2}),以此类推。这样,我们就这种类型的边的数量减少到了(log)级别。然后建图跑最短路即可。

    代码

    #include <iostream>
    #include <cstdio>
    #include <queue>
    #include <cstring>
    #define N 100002
    #define M 5000002
    using namespace std;
    int head[N],ver[M],nxt[M],edge[M],l;
    int n,m,c,s,t,i,j,dis[N];
    int read()
    {
    	char c=getchar();
    	int w=0;
    	while(c<'0'||c>'9') c=getchar();
    	while(c<='9'&&c>='0'){
    		w=w*10+c-'0';
    		c=getchar();
    	}
    	return w;
    }
    void insert(int x,int y,int z)
    {
    	l++;
    	ver[l]=y;
    	edge[l]=z;
    	nxt[l]=head[x];
    	head[x]=l;
    }
    void Dijkstra()
    {
    	priority_queue<pair<int,int> > q;
    	memset(dis,0x3f,sizeof(dis));
    	q.push(make_pair(0,s));
    	dis[s]=0;
    	while(!q.empty()){
    		int x=q.top().second,d=-q.top().first;
    		q.pop();
    		if(d!=dis[x]) continue;
    		for(int i=head[x];i;i=nxt[i]){
    			int y=ver[i];
    			if(dis[y]>dis[x]+edge[i]){
    				dis[y]=dis[x]+edge[i];
    				q.push(make_pair(-dis[y],y));
    			}
    		}
    	}
    }
    int main()
    {
    	n=read();m=read();c=read();
    	for(i=1;i<=m;i++){
    		int u=read(),v=read(),w=read();
    		insert(u,v,w);
    	}
    	for(i=0;i<=n;i++){
    		for(j=0;(1<<j)<=n;j++){
    			if((i^(1<<j))>n) continue;
    			insert(i,(i^(1<<j)),(1<<j)*c);
    		}
    	}
    	s=read();t=read();
    	Dijkstra();
    	printf("%d
    ",dis[t]);
    	return 0;
    }
    
    
  • 相关阅读:
    线程安全
    Kafka分区原理图
    Zookeeper02
    Zookeeper01
    kafka01
    20170623_oracle_SQL
    20170623_oracle备份和恢复_常见问题
    20170623_oracle基础知识_常见问题
    数字类型入门
    数据类型基础
  • 原文地址:https://www.cnblogs.com/LSlzf/p/12208838.html
Copyright © 2011-2022 走看看