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

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

思路:
  首先Dijkstra求出从1出发到每个结点$i$的单源最短路$dis[i]$及经过的第一个结点$first[i]$。
  考虑重构图,将起点与终点区分开来,新建结点$n+1$表示终点。
  枚举原图中的每一条边$(x,y,w)$,表示从$x$到$y$边权为$w$。
  若$x=1,first[y]\ne y$,在新图中保留这条边;
  若$y=1,first[x]\ne x$,说明存在一条从$1$沿最短路到$x$再到$1$的合法路径,在新图中连边$(1,n+1,w)$;
  若$y=1,first[x]=x$,在新图中保留这条边;
  若$x\ne1,y\ne1,first[x]\ne first[y]$,说明存在一条从$1$沿最短路到$x$再到$y$再沿最短路到$1$的合法路径,连边$(1,y,dis[x]+w)$;
  若$x\ne1,y\ne1,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\n",dis[n]==INT_MAX?-1:dis[n]);
64     return 0;
65 }

 

posted @ 2018-03-23 13:59  skylee03  阅读(155)  评论(0编辑  收藏  举报