• Dij--P4366 [Code+#4]最短路


    *传送

    题意: 给定$n$个点,求从$s$到$t$的最短路径,其中有两种走法(可以混搭):一种是走给定的m有向边($u_i$,$v_i$,$w_i$);另一种可以由任意点x到任意点y,其费用是$c$ $ imes$ ($x$ $xor$ $y$)

    朴素的建法是$O$ ($n^2$ $ imes$ $m$)的.然而事实上一个从$x$$ o$ $y$权值为$w$的边是可以被其他边取代的,我们可以把$x$拆成二进制,一位一位的修改最终到达y,此时经过的权值显然也是$w$。

    举个例子:

    假设我们要从 $001_2$​ 到 $010_2$​,我们要花费 $2^0$ +$ 2^1$ 的费用; 但是,最短路有一个 优越的性质,我们可以把边拆开来,可以先从 $001_2$​ 到$ 000_2$,再从$ 000_2$​ 到$ 010_2$,费用是一样的。

    也就是说,对于一个点$x$,我们只需要让他和$x$ $ imes$ $2^k$连边即可,这样就优化为$O$($nlogn$+$m$)了,跑一遍$dij$就好了。

    代码:

     1 #include <iostream>
     2 #include <cstring>
     3 #include <cstdio>
     4 #include <algorithm>
     5 #include <queue> 
     6 #include <cmath>
     7 using namespace std;
     8 int n,m,c,st,sd,x,y,val;
     9 struct node{
    10     int to,next,w;
    11 }ed[5000005];
    12 int dis[5000005],vis[5000005],head[5000005],cnt;
    13 inline void add(int u,int v,int w){
    14     ed[++cnt].next=head[u];
    15     ed[cnt].to=v;
    16     ed[cnt].w=w;
    17     head[u]=cnt;
    18 }
    19 inline int read(){
    20     int x = 1,a = 0;
    21     char ch = getchar();
    22     while(ch < '0' || ch > '9'){
    23         if(ch == '-')x = -1;
    24         ch = getchar();
    25     }
    26     while(ch <= '9'&&ch >= '0'){
    27         a = a * 10 + ch - '0';
    28         ch = getchar();
    29     }
    30     return x*a;
    31 }
    32 priority_queue<pair<int,int> > q;
    33 inline void Dij(int s){
    34     q.push(make_pair(0,s));memset(vis,0,sizeof(vis));memset(dis,63,sizeof(dis));dis[s]=0;
    35     while (!q.empty()){
    36         int x = q.top().second;
    37         q.pop();
    38         if (vis[x]) continue;
    39         vis[x]=1;
    40         for (register int i = head[x];i;i=ed[i].next){
    41             int to = ed[i].to;
    42             if (dis[to]>dis[x]+ed[i].w){
    43                 dis[to]=dis[x]+ed[i].w;
    44                 q.push(make_pair(-dis[to],to));
    45             }
    46         }
    47     }
    48     return;
    49 }
    50 int main(){
    51     n=read();m=read();c=read();
    52     for (int i = 1;i <= m;i++){
    53         x=read(),y=read(),val=read();
    54         add(x,y,val);
    55     }
    56     int lgn = floor(log2(n)) + 1;
    57     n = (1 << lgn) - 1;
    58     for (register int i = 1;i <= n;i++)
    59         for (register int j = 0;j < lgn;j++)
    60             add(i,i^(1<<j),(1<<j)*c);
    61     st=read(),sd=read();
    62     Dij(st);
    63     cout<<dis[sd];
    64 }
  • 相关阅读:
    Everspin MRAM技术的可靠性
    如何减小SRAM读写操作时的串扰
    SRAM电路工作原理
    关于如何提高SRAM存储器的新方法
    低功耗SRAM主要三部分功耗来源
    [小米OJ] 6. 交叉队列
    [小米OJ] 4. 最长连续数列
    [小米OJ] 5. 找出旋转有序数列的中间值
    [小米OJ] 3. 大数相减
    [剑指offer] 66. 机器人的运动范围
  • 原文地址:https://www.cnblogs.com/very-beginning/p/12732809.html
Copyright © 2020-2023  润新知