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

时间: 2024-10-17 22:08:37

bzoj2407 探险 (重构图 + 最短路)的相关文章

Atcoder Snuke&#39;s Subway Trip 重构图

题目链接 这题主要是重构图的方法很难思考. 方法一:考虑在每个公司意义下的联通块,每个联通块对应一个虚拟节点,联通块内的节点到联通块对应的虚拟节点有一条边,构建出一个二分图,跑一遍BFS,将经过的边数除以2.这里有两种实现,                             细节都注释在了程序里 1 #include<bits/stdc++.h> 2 using namespace std; 3 vector<pair<int,int> > nei[1000005

【UVA10603】Fill (构图+最短路)

题目: Sample Input22 3 4 296 97 199 62Sample Output2 29859 62 题意: 有三个杯子它们的容量分别是a,b,c, 并且初始状态下第一个和第二个是空的, 第三个杯子是满水的.可以把一个杯子的水倒入另一个杯子,当然,当被倒的杯子满了或者倒的杯子水完了,就不能继续倒了. 你的任务是写一个程序计算出用最少的倒水量,使得其中一个杯子里有d升水.如果不能倒出d升水的话,那么找到一个d' < d ,使得d' 最接近d. 分析: 可以把每个状态即3个水杯里的

O - Marriage Match IV - hdu 3416(最短路+最大流)

题目大意:在城市A的男孩想去城市B的女孩,不过他去城市B必须走最短路,并且走过的路不可以再走,问他最多能看这个女孩多少次.   分析:因为这个男孩直走最短路,所以我们必须求出来所有最短路径上的路,怎么判断一条路是否属于最短路经上的呢?其实比较容易的,只要先求出来从A到达所有点的最短路distA[x], 然后再求出来所有点到B的最短路distB[y](添加反边从B开始即可求出),如果x-y之间有一条路,那么只需要判断distA[x]+distB[y]+w(x,y) == distA[B] 是否成立

P3106 [USACO14OPEN]GPS的决斗(最短路)

化简:够简的了.....但是!翻译绝对有锅. 这个最短路是从n到每个点的单源最短路,也就是最短路径树. 那么,思路就很明确了.建两个图,然后跑两边SPFA,记录下最短路径. 然后,对于两点之间的边,如果最短路不经过它,那么最终图边权+1: 然后在最终图上(边权为0,1,2)跑一遍SPFA即可. 一开始我想复杂了,在想怎么记录路径,怎么重构图.balabala. 然后发现,怎么才能让两点不在最短路径上呢? SPFA的松弛操作,依据是三角不等式.于是,如果两点之间的最短路的距离如果不等于边权(也就是

【司雨寒】最短路专题总结

最近在刷郏老大博客上的最短路专题 [HDU] 1548            A strange lift                    基础最短路(或bfs) 1 //#define LOCAL 2 #include <iostream> 3 #include <cstdio> 4 #include <cstring> 5 using namespace std; 6 7 const int maxn = 200 + 10; 8 struct Point 9

【BZOJ-1179】Atm Tarjan + SPFA

1179: [Apio2009]Atm Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 2407  Solved: 993[Submit][Status][Discuss] Description Input 第一行包含两个整数N.M.N表示路口的个数,M表示道路条数.接下来M行,每行两个整数,这两个整数都在1到N之间,第i+1行的两个整数表示第i条道路的起点和终点的路口编号.接下来N行,每行一个整数,按顺序表示每个路口处的ATM机中的钱数.接下来

GDOI2015滚粗记

好吧.我人生最后一次GDOI就这么愉快地滚粗啦.... 现在回过头来总结一下,发现我有时候真的是too naive了.策略方面真的不够成熟.. 首先Day1吧..不忍回忆的一天... 按照程序先浏览题目,决定从第一题开始搞.一开始它的样例是错的,我还以为我看错题了,!·#¥¥%,研究题目就研究了半个钟,,,我擦..改完样例之后题意就比较容易明白了 我很快想到了是Bfs两次,但一时脑抽没有想到根据条件重构图,,直接在原图上Bfs,实现的时候有很多地方没有想好怎么处理,这样又差不多耗了半个钟,想到一

Broken Dream-GDOI 2017

初中第一场GDOI吧..或许是最后一场了..知道自己实力弱,肯定会考挂,但没想到崩的这么惨..唉.. GDOI前就学了一下以前没搞懂的算法,刷了一些模板题,感觉水平还是有些提高的.. 只不过每天中午去机房刷题,晚上经常熬夜写作业,然后凌晨四五点起来刷题背模板,还是坚持了一个月,真的挺累的(人太弱就得这样)(结果还是考挂).. Day -1 晚上写了一下五一假期的作业,背了一下模板,收拾了一下行李,就去睡觉了.(想起GDOI能躲掉各种考试,莫名excited).. Day 0 9点多坐车去高铁站,

解题报告 之 HDU5294 Tricks Device

解题报告 之 HDU5294 Tricks Device Description Innocent Wu follows Dumb Zhang into a ancient tomb. Innocent Wu's at the entrance of the tomb while Dumb Zhang's at the end of it. The tomb is made up of many chambers, the total number is N. And there are M c