题解 P4366 【[Code+#4]最短路】

题目链接

Solution [Code+#4]最短路

题目大意:图上任意两点(u,v)间有权值为((u;xor;v) imes c)的无向边,再添加给定的(m)条有向边之后,询问(s)(t)的最短路

最短路


分析:首先给定的有向边我们肯定直接连上,剩下的无向边规模极大直接跑最短路会炸掉

我们考虑去除无用的边,如果当前点为(u),就将(u)与和它二进制表示只有一位不同的(v)连边。如果((u,v))直接的连边被去掉了,它可以通过图上路径表示出来,不会影响正确性

边的规模便可以降到(O(nlogn))

#include <cstdio>
#include <cctype>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
const int maxn = 1e5 + 100;
inline int read(){
    int x = 0;char c = getchar();
    while(!isdigit(c))c = getchar();
    while(isdigit(c))x = x * 10 + c - '0',c = getchar();
    return x;
}
struct edge{int v,d;};
vector<edge> G[maxn];
inline void addedge(int u,int v,int d){
    G[u].push_back(edge{v,d});}
int vis[maxn],dis[maxn],n,m,c,s,t;
struct node{
    int u,h;
    bool operator < (const node &rhs)const{
        return h > rhs.h;
    }
};
priority_queue<node> Q;
inline void dijkstra(int s){
    memset(dis,0x3f,sizeof(dis));
    dis[s] = 0;Q.push(node{s,0});
    while(!Q.empty()){
        int u = Q.top().u;Q.pop();
        if(vis[u])continue;
        vis[u] = 1;
        for(auto e : G[u]){
            if(dis[u] + e.d < dis[e.v]){
                dis[e.v] = dis[u] + e.d;
                Q.push(node{e.v,dis[e.v]});
            }
        }
        for(int i = 20;i >= 0;i--)
            if((u ^ (1 << i)) <= n && (dis[u] + (1 << i) * c) < dis[u ^ (1 << i)]){
                dis[u ^ (1 << i)] = dis[u] + (1 << i) * c;
                Q.push(node{u ^ (1 << i),dis[u ^ (1 << i)]});
            }
    }
}
int main(){
    n = read(),m = read(),c = read();
    for(int u,v,d,i = 1;i <= m;i++)
        u = read(),v = read(),d = read(),addedge(u,v,d);
    s = read(),t = read();
    dijkstra(s);
    printf("%d
",dis[t]);
    return 0;
}
原文地址:https://www.cnblogs.com/colazcy/p/13537633.html