[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 }