Codevs 1021 (玛丽卡)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codevs 1021 (玛丽卡)相关的知识,希望对你有一定的参考价值。

题目描述 Description

麦克找了个新女朋友,玛丽卡对他非常恼火并伺机报复。

因为她和他们不住在同一个城市,因此她开始准备她的长途旅行。

在这个国家中每两个城市之间最多只有一条路相通,并且我们知道从一个城市到另一个城市路上所需花费的时间。

麦克在车中无意中听到有一条路正在维修,并且那儿正堵车,但没听清楚到底是哪一条路。无论哪一条路正在维修,从玛丽卡所在的城市都能到达麦克所在的城市。

玛丽卡将只从不堵车的路上通过,并且她将按最短路线行车。麦克希望知道在最糟糕的情况下玛丽卡到达他所在的城市需要多长时间,这样他就能保证他的女朋友离开该城市足够远。

编写程序,帮助麦克找出玛丽卡按最短路线通过不堵车道路到达他所在城市所需的最长时间(用分钟表示)。

输入描述 Input Description
第一行有两个用空格隔开的数N和M,分别表示城市的数量以及城市间道路的数量。1≤N≤1000,1≤M≤N*(N-1)/2。城市用数字1至N标识,麦克在城市1中,玛丽卡在城市N中。

接下来的M行中每行包含三个用空格隔开的数A,B和V。其中1≤A,B≤N,1≤V≤1000。这些数字表示在A和城市B中间有一条双行道,并且在V分钟内是就能通过。

 

输出描述 Output Description
输出文件的第一行中写出用分钟表示的最长时间,在这段时间中,无论哪条路在堵车,玛丽卡应该能够到达麦克处,如果少于这个时间的话,则必定存在一条路,该条路一旦堵车,玛丽卡就不能够赶到麦克处。

样例输入 Sample Input
5 7

1 2 8

1 4 10

2 3 9

2 4 10

2 5 1

3 4 7

3 5 10

样例输出 Sample Output
27

 时间限制: 2 s
 空间限制: 128000 KB
题目来源:codevs
   题目让我们所求的是最坏的情况,我们可以用SPFA跑一边最短路,然后记录这个最短路所经过的路径然后一一枚举边,将那条边标记为堵车,再求一边最短路路径,,我们可以得到每一组的由n到1城市的最短耗费时间是多少,在与ans比较取最大值,当原先的最短路径上锁经过的边枚举完以后,我们就可以得到最坏的情况所耗费的时间。(样例中,我们可以由5走到2 耗费1的时间,然后再由2走到1,耗费8的时间,在不堵车的情况下9就是最短花费时间,在这时我们将ans更新为9。然后将最优解的第一条边设置为堵车,我们就得先从5走到3,耗费10,再从3走到2耗费9,再从2走到1耗费8,总耗费是27,大于9,所以ans更新为27。在处理最优解得的第二条边,首先从5走到2耗费1,再从2走到4耗费为10,再从4走到1耗费为10,总耗费为21,但没大于ans的值,所以不是最坏的情况,所以output27
   因为时间限制为2s,最开始觉得记录最优解的边太麻烦了,于是就打算每条边都设置为堵车一次,暴力下来这道题,但是题目中的边数根据公式推出来大约是1e7左右,如果这样算的话,2s是不够的,所以必须记录最优解所经过的边,记录边是ac这道题的重点。
    对于这一点我们可以开一个f数组,因为用的SPFA,所以f[i]表示的是在目前情况下,到达i的最优解的上一条路的起点是f[i]。我们可以if(d[queue[Head]]+e[i].aim<d[e[i].lon])这条语句成立以后,找到新的最短路,我们可以将f[i]更新为queue[head]。
技术分享

 

 比如在这个城市当中,我们从一号城市开始找,一号城市找完以后f[2]=1,f[4]=1,f[3]=1。然后根距入队顺序找下一条边(这里假定入队为2,4,3)。然后开始从二号城市开始找,搜索到了3和5,f[5]=2,因为2+4>2不是1号城市到3号城市的最优解,所以f[3]的值不更新,走到四号城市,搜索到了1,4,6同理f[3]=1,f[5]=2,f[6]=4。接下来队里的是三号城市,会发现2+5<11,说明从1号城市到3号再到4号城市为1到4的最优解,所以将f[4]更新为3,剩下推到过程省略。。
所以当SPFA结束后用for(i=n;i!=0;i=f[i])就可以搜索出来最优解经过的所以路径。
    重点讲完了,下面开始粘代码。

注意数组一定要开够,codevs上数组没有开够不会显示re,会显示tle。

 

技术分享
 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 #define  maxn 2147483647
 5 int point;
 6 struct node{
 7  int aim,lon,next,ex;
 8 };
 9 node e[1000005];
10 int head[1005],Head,tail,f[1005],queue[30005],d[1005],m,n;
11 bool dui[1000005],flag[1000005];
12 void add(int x,int y,int z,int t)
13 {
14  point ++;
15  e[point].next=head[x];
16  head[x]=point;
17  e[point].lon=y;
18  e[point].aim=z;
19  e[point].ex=t;
20 }
21 
22 void spfa(int a)
23 {
24  while(Head<tail)
25  {
26   for(int i=head[queue[Head]];i!=0;i=e[i].next)
27   {
28     if(flag[e[i].ex]==true)continue;
29    if(d[queue[Head]]+e[i].aim<d[e[i].lon])
30    {
31        if(a==0)f[e[i].lon]=queue[Head];
32     d[e[i].lon]=d[queue[Head]]+e[i].aim;
33     if(!dui[e[i].lon]){queue[tail++]=e[i].lon;dui[e[i].lon]=true;}
34    }
35   }
36   dui[queue[Head]]=false;
37   Head++;
38  }
39 }
40 
41 void prepare()
42 {
43  for(int i=1;i<=n;i++)
44  d[i]=maxn;
45   Head=1;
46   tail=2;
47   dui[1]=true;
48   queue[1]=1;
49   d[1]=0;
50 }
51 int main()
52 {
53  scanf("%d%d",&n,&m);
54  for(int i=1;i<=m;i++)
55   {
56   int x,y,z;
57   scanf("%d%d%d",&x,&y,&z);
58     add(x,y,z,point+2);
59     add(y,x,z,point);
60    }
61    prepare();
62   spfa(0);
63   int ans=d[n];
64   prepare();
65   int t=n;
66   for(int i=f[n];i!=0;i=f[i])
67   {
68     int q,p;
69   for(int j=head[i];j!=0;j=e[j].next)
70   if(e[j].lon==t){
71     q=j;
72     flag[e[j].ex]=true;
73     if(j%2){flag[e[j+1].ex]=true;p=j+1;}
74     else {flag[e[j-1].ex]=true;
75     p=j-1;} 
76     break;
77   }
78   spfa(1);
79   if(d[n]>ans)ans=d[n];
80     flag[e[p].ex]=flag[e[q].ex]=false;
81   prepare();
82   t=i;
83  }
84  printf("%d ",ans);
85  return 0;
86 }
View Code

 

以上是关于Codevs 1021 (玛丽卡)的主要内容,如果未能解决你的问题,请参考以下文章

Codevs 1021 (玛丽卡)

codevs1021 玛丽卡

洛谷P1186 CodeVS1021 玛丽卡

codevs 1021 玛丽卡(spfa)

codevs 1021 玛丽卡x

codevs 1021 玛丽卡(spfa)