bzoj2407 探险 (重构图 + 最短路)
Posted Sinogi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj2407 探险 (重构图 + 最短路)相关的知识,希望对你有一定的参考价值。
2407: 探险
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 148 Solved: 84
[Submit][Status][Discuss]
Description
探险家小T好高兴!X国要举办一次溶洞探险比赛,获奖者将得到丰厚奖品哦!小T虽然对奖品不感兴趣,但是这个大振名声的机会当然不能错过!
比赛即将开始,工作人员说明了这次比赛的规则:每个溶洞和其他某些溶洞有暗道相连。两个溶洞之间可能有多条道路,也有可能没有,但没有一条暗道直接从自己连到自己。参赛者需要统一从一个大溶洞出发,并再次回到这个大溶洞。
如果就这么点限制,那么问题就太简单了,可是举办方又提出了一个条件:不能经过同一条暗道两次。这个条件让大家犯难了。这该怎么办呢?
到了大溶洞口后,小T愉悦地发现这个地方他曾经来过,他还记得有哪些暗道,以及通过每条暗道的时间。小T现在向你求助,你能帮他算出至少要多少时间才能回到大溶洞吗?
Input
第一行两个数n,m表示溶洞的数量以及暗道的数量。
Output
(直接抄dalao的题解了orz)
先跑一遍最短路,令 1 到 i 的最短路为 dis [ i ],并记录 1 到 i 的最短路上第一个经过的点 pre [ i ],如 pre [ i ] = 1则 pre [ i ] = i ;
重新构图,对于原图中的一条边(u,v,w):
若 u = 1:
若 pre [ v ] = v ,忽略此边;否则连边(S,v,w);
若 v = 1:
若 pre [ u ] = u,连边(u,T,w);否则连边(S,T,dis [ u ] + w);
若 u!=1 && v!=1:
若 pre [ u ] = pre [ v ],连边(u,v,w);否则连边(S,v,dis [ u ] + w);
新图中跑一边 S 到 T 最短路即可;
这样构造把 S -> i 的边拆开,就不会导致一条路走两遍;
AC GET☆DAZE
↓代码
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<string> 5 #include<cmath> 6 #include<algorithm> 7 #include<vector> 8 #include<queue> 9 using namespace std; 10 struct edge 11 { 12 int to,next,val; 13 }fet[400039],ret[400039]; 14 int n,fhd[40039],shd[40039],tot,rot,dis[40039],fir[40039],S,T,stp=0x3f3f3f3f; 15 bool inq[40039],Sinogi[40039]; 16 void add(int u,int v,int ws,int wr) 17 { 18 fet[++tot].to=v,fet[tot].next=fhd[u],fet[tot].val=ws,fhd[u]=tot; 19 fet[++tot].to=u,fet[tot].next=fhd[v],fet[tot].val=wr,fhd[v]=tot; 20 } 21 void add(int u,int v,int w) 22 { 23 ret[++rot].to=v,ret[rot].next=shd[u],ret[rot].val=w,shd[u]=rot; 24 } 25 void spfa(edge net[],int head[]) 26 { 27 memset(dis,63,sizeof(dis)); 28 queue<int>que; 29 que.push(S),dis[S]=0,inq[S]=1,fir[S]=S; 30 int a,b; 31 while(!que.empty()) 32 { 33 a=que.front(),que.pop(); 34 for(b=head[a];b!=-1;b=net[b].next) 35 { 36 if(dis[net[b].to]>dis[a]+net[b].val) 37 { 38 dis[net[b].to]=dis[a]+net[b].val; 39 fir[net[b].to]=(fir[a]==S ? net[b].to : fir[a]); 40 if(!inq[net[b].to]) 41 { 42 que.push(net[b].to); 43 inq[net[b].to]=1; 44 } 45 } 46 } 47 inq[a]=0; 48 } 49 } 50 void rebuild(edge net[],int head[]) 51 { 52 int a,b; 53 for(a=1;a<=n;a++) 54 { 55 for(b=head[a];b!=-1;b=net[b].next) 56 { 57 if(a==S) 58 { 59 if(fir[net[b].to]!=net[b].to) 60 { 61 add(1,net[b].to,net[b].val); 62 } 63 } 64 else if(net[b].to==S) 65 { 66 if(fir[a]!=a) 67 { 68 add(S,T,dis[a]+net[b].val); 69 } 70 else 71 { 72 add(a,T,net[b].val); 73 } 74 } 75 else 76 { 77 if(fir[a]!=fir[net[b].to]) 78 { 79 add(S,net[b].to,dis[a]+net[b].val); 80 } 81 else 82 { 83 add(a,net[b].to,net[b].val); 84 } 85 } 86 } 87 } 88 } 89 int main() 90 { 91 memset(fhd,-1,sizeof(fhd)); 92 memset(shd,-1,sizeof(shd)); 93 int m,ans=0x3f3f3f3f,a,b,c,d,e; 94 scanf("%d%d",&n,&m); 95 for(a=1;a<=m;a++) 96 { 97 scanf("%d%d%d%d",&b,&c,&d,&e); 98 if(b==1) 99 { 100 Sinogi[c]=1,dis[c]=d; 101 } 102 if(c==1 && Sinogi[b]) 103 { 104 stp=min(stp,d+dis[b]); 105 } 106 add(b,c,d,e); 107 } 108 S=1; 109 spfa(fet,fhd); 110 T=n+1; 111 rebuild(fet,fhd); 112 spfa(ret,shd); 113 printf("%d",min(stp,dis[T])); 114 return 0; 115 }
以上是关于bzoj2407 探险 (重构图 + 最短路)的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ 2156 「国家集训队」星际探索(最短路)BZOJ计划
BZOJ 2156 「国家集训队」星际探索(最短路)BZOJ计划