首页 > 其他分享 >1006 最短路 dijkstra 异或运算变化的精简操作

1006 最短路 dijkstra 异或运算变化的精简操作

时间:2022-08-17 22:46:40浏览次数:97  
标签:dist int 城市 dijkstra cin vis 异或 1006 ver

 链接:https://ac.nowcoder.com/acm/contest/26077/1006
来源:牛客网

题目描述

企鹅国中有NNN座城市,编号从111到NNN。
对于任意的两座城市iii和jjj,企鹅们可以花费(i  xor  j)∗C(i\,\,xor\,\, j)*C(ixorj)∗C的时间从城市iii走到城市jjj,这里CCC为一个给定的常数。
当然除此之外还有MMM条单向的快捷通道,第i条快捷通道从第FiF_iFi​个城市通向第TiT_iTi​个城市,走这条通道需要消耗ViV_iVi​的时间。
现在来自Penguin Kingdom University的企鹅豆豆正在考虑从城市AAA前往城市BBB最少需要多少时间?


输入描述:

输入第一行包含三个整数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),表示企鹅豆豆选择的起点城市标号和终点城市标号。

输出描述:

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

输入

复制
4 2 1
1 3 1
2 4 4
1 4

输出

复制
5

说明

直接从 1 走到 4 就好了。   
示例2

输入

复制
7 2 10
1 3 1
2 4 4
3 6

输出

复制
34

说明

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

备注:

分析

图片太小了,看了别人的提交才知道数据范围是1e7。。。

这道题加入了 i ^ j 为两点距离。如果暴力跑1e10会超时。所以需要根据位运算的特性精简边数。

i 和 j 的差别就是 1 的位置和数量。

首先先忽略直通路径

对于每对i ,j来说。从i 到 j 有两种方式

一种是i 经过其它点k 到达 j 花费是 i ^ k + k ^ j

一种是i 直接到达 j 花费是i ^ j

如果k 的1 的位置都和 i 与 j 重复,那多一个k 就多了差不多一倍的消耗

每个点到另一个点都是选择直接走到另一个点而不借助其它点的花费最少

对最短路长度的贡献,取决于两者不同1的位置和数量,一旦引入其它点会导致位数贡献变多,不是最优

现在把贡献拆开,i 和 j 的位置差别可能不止一位。要使i 变成 j ,i 就需要把自己连向和自己只差一位的点,这样经过有限次变动,i 就可以变成 j。每次移动都是 i 和 j 不同的位数 所以答案不会变差。

按照这样精简边数就可以跑最短路。

//-------------------------代码----------------------------

//#define int ll
const int N = 1e7+10;
int n,m,c;

int e[N],ne[N],w[N],h[N],idx;
int dist[N];bool vis[N];
void add(int a,int b,int c) {
    e[idx] = b,ne[idx] = h[a],w[idx] = c,h[a] = idx++ ;
}
int st,ed;
void dij() {
    ms(dist,0x3f);
    ms(vis,0);
    priority_queue<pii,V<pii>,greater<pii>> q;
    q.push({0,st});
    dist[st] =  0;
    while(q.size()) {
        auto t = q.top();q.pop();
        int ver = t.second,W = t.first;
        if(vis[ver]) continue;
        vis[ver] = 1;
        for(int i = h[ver];~i;i=ne[i]) {
            if(vis[e[i]]) continue;
            if(dist[e[i]] > W + w[i]) {
                dist[e[i]] = dist[ver] + w[i]; 
                q.push({dist[e[i]],e[i]});
            }
        }
    }
}

void solve()
{
    cin>>n>>m>>c;
    ms(h,-1);
    fo(i,1,m) {
        int x,y,z;cin>>x>>y>>z;
        add(x,y,z);
    }
    fo(i,0,n) {
        for(int j = 1;j<=n;j<<=1) {
            if((i ^ j) > n)continue;
            add(i,i^j,j*c);
        }
    }
    cin>>st>>ed;
    dij();
    cout<<dist[ed]<<endl;
}
void main_init() {}
signed main(){
    AC();clapping();TLE;
    cout<<fixed<<setprecision(12);
    main_init();
//  while(cin>>n,n)
//  while(cin>>n>>m,n,m)
//    int t;cin>>t;while(t -- )
    solve();
//    {solve(); }
    return 0;
}

/*样例区


*/

//------------------------------------------------------------

 

标签:dist,int,城市,dijkstra,cin,vis,异或,1006,ver
From: https://www.cnblogs.com/er007/p/16597037.html

相关文章

  • 开关(线段树区间异或板子)
    [TJOI2009]开关题目描述现有\(n\)盏灯排成一排,从左到右依次编号为:\(1\),\(2\),……,\(n\)。然后依次执行\(m\)项操作。操作分为两种:指定一个区间\([a,b]\),然后改变......
  • swap(a, b)异或骚操作方法
    众所周知,平日里我们如果要交换两个变量的时候,通常都是voidswap(inta,intb){inttemp=a;a=b;b=temp;}通过创建temp变量,保存其中一个的值,再交......
  • 子数组异或和(前缀和、哈希)
    题意给定一个长度为\(n\)的整数数组\(a_1,a_2,\dots,a_n\)。请你统计一共有多少个数组\(a\)的非空连续子数组能够同时满足以下所有条件:该连续子数组的长度为偶数。......
  • 1007 公交线路 dijkstra板子+总结
     链接:https://ac.nowcoder.com/acm/contest/26077/1007来源:牛客网题目描述P市有n个公交站,之间连接着m条道路。P市计划新开设一条公交线路,该......
  • 1006 Sign In and Sign Out(25分)
    Atthebeginningofeveryday,thefirstpersonwhosignsinthecomputerroomwillunlockthedoor,andthelastonewhosignsoutwilllockthedoor.Givent......
  • [AcWing 4507] 子数组异或和
    异或的性质点击查看代码#include<bits/stdc++.h>usingnamespacestd;typedeflonglongLL;constintN=1e6+10;intn;inta[N];voidsolve(){......
  • Acwing 第 64 场周赛 C 4507. 子数组异或和(异或+前缀和)
    https://www.acwing.com/problem/content/4510/给定一个长度为n的整数数组a1,a2,…,an。请你统计一共有多少个数组a的非空连续子数组能够同时满足以下所有条件:该......