• [BZOJ4398]福慧双修/[BZOJ2407]探险


    题目大意:
      给定一个$n(nleq40000)$个点$m(mleq100000)$条边的有向图,求从$1$出发回到$1$的不经过重复结点的最短路。

    思路:
      首先Dijkstra求出从1出发到每个结点$i$的单源最短路$dis[i]$及经过的第一个结点$first[i]$。
      考虑重构图,将起点与终点区分开来,新建结点$n+1$表示终点。
      枚举原图中的每一条边$(x,y,w)$,表示从$x$到$y$边权为$w$。
      若$x=1,first[y] e y$,在新图中保留这条边;
      若$y=1,first[x] e x$,说明存在一条从$1$沿最短路到$x$再到$1$的合法路径,在新图中连边$(1,n+1,w)$;
      若$y=1,first[x]=x$,在新图中保留这条边;
      若$x e1,y e1,first[x] e first[y]$,说明存在一条从$1$沿最短路到$x$再到$y$再沿最短路到$1$的合法路径,连边$(1,y,dis[x]+w)$;
      若$x e1,y e1,first[x]=first[y]$,在新图中保留这条边。
      最后再求一遍从$1$到$n+1$的最短路即可。

     1 #include<list>
     2 #include<cstdio>
     3 #include<cctype>
     4 #include<climits>
     5 #include<functional>
     6 #include<ext/pb_ds/priority_queue.hpp>
     7 inline int getint() {
     8     register char ch;
     9     while(!isdigit(ch=getchar()));
    10     register int x=ch^'0';
    11     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    12     return x;
    13 }
    14 const int N=40002;
    15 typedef std::pair<int,int> Edge;
    16 typedef std::list<Edge> List;
    17 typedef std::pair<int,int> Vertex;
    18 typedef __gnu_pbds::priority_queue<Vertex,std::greater<Vertex> > Heap;
    19 int n,dis[N],first[N];
    20 List e[N];
    21 inline void add_edge(const int &u,const int &v,const int &w) {
    22     e[u].push_front((Edge){v,w});
    23 }
    24 void dijkstra() {
    25     static Heap q;
    26     static Heap::point_iterator p[N];
    27     for(register int i=1;i<=n;i++) {
    28         p[i]=q.push((Vertex){dis[i]=i==1?0:INT_MAX,i});
    29     }
    30     while(!q.empty()) {
    31         const int &x=q.top().second;
    32         for(register List::iterator i=e[x].begin();i!=e[x].end();i++) {
    33             const int &y=i->first,&w=i->second;
    34             if(dis[x]+w<dis[y]) {
    35                 first[y]=x==1?y:first[x];
    36                 q.modify(p[y],(Vertex){dis[y]=dis[x]+w,y});
    37             }
    38         }
    39         q.pop();
    40     }
    41 }
    42 void rebuild() {
    43     n++;
    44     for(register int x=1;x<=n;x++) {
    45         for(register List::iterator i=e[x].begin();i!=e[x].end();e[x].erase(i++)) {
    46             const int &y=i->first,&w=i->second;
    47             if(x==1&&first[y]!=y) add_edge(1,y,w);
    48             if(y==1) first[x]==x?add_edge(x,n,w):add_edge(1,n,dis[x]+w);
    49             if(x!=1&&y!=1) first[x]==first[y]?add_edge(x,y,w):add_edge(1,y,dis[x]+w);
    50         }
    51     }
    52 }
    53 int main() {
    54     n=getint();
    55     for(register int m=getint();m;m--) {
    56         const int u=getint(),v=getint();
    57         add_edge(u,v,getint());
    58         add_edge(v,u,getint());
    59     }
    60     dijkstra();
    61     rebuild();
    62     dijkstra();
    63     printf("%d
    ",dis[n]==INT_MAX?-1:dis[n]);
    64     return 0;
    65 }
  • 相关阅读:
    内置函数(十)
    常用命令
    函数式编程(九)——map,filter,reduce
    函数(八)-函数和匿名函数
    设计模式(十三)——观察者模式
    Confluence 6 重要缓存和监控
    Confluence 6 数据中心的缓存
    Confluence 6 配置文件和key
    Confluence 6 缓存性能示例
    Confluence 6 缓存性能优化
  • 原文地址:https://www.cnblogs.com/skylee03/p/8629966.html
Copyright © 2020-2023  润新知