bzoj2407 探险 (重构图 + 最短路)

2407: 探险

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 148  Solved: 84
[Submit][Status][Discuss]

Description

探险家小T好高兴!X国要举办一次溶洞探险比赛,获奖者将得到丰厚奖品哦!小T虽然对奖品不感兴趣,但是这个大振名声的机会当然不能错过!

比赛即将开始,工作人员说明了这次比赛的规则:每个溶洞和其他某些溶洞有暗道相连。两个溶洞之间可能有多条道路,也有可能没有,但没有一条暗道直接从自己连到自己。参赛者需要统一从一个大溶洞出发,并再次回到这个大溶洞。

如果就这么点限制,那么问题就太简单了,可是举办方又提出了一个条件:不能经过同一条暗道两次。这个条件让大家犯难了。这该怎么办呢?

到了大溶洞口后,小T愉悦地发现这个地方他曾经来过,他还记得有哪些暗道,以及通过每条暗道的时间。小T现在向你求助,你能帮他算出至少要多少时间才能回到大溶洞吗?

Input

第一行两个数n,m表示溶洞的数量以及暗道的数量。

接下来m行,每行4个数s、t、w、v,表示一个暗道连接的两个溶洞s、t,这条暗道正着走(s -> t)的所需要的时间w,倒着走(t -> s)所需要的时间v。由于溶洞的相对位置不同,wv可能不同。

Output

输出一行一个数t,表示最少所需要的时间。

 

 

(直接抄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
散りぬべき 時知りてこそ 世の中の 花も花なれ 人も人なれ
原文地址:https://www.cnblogs.com/Sinogi/p/7458321.html