【洛谷】P2865 [USACO06NOV]Roadblocks G 题解

贝茜把家搬到了一个小农场,但她常常回到 $FJ $的农场去拜访她的朋友。贝茜很喜欢路边的风景,不想那么快地结束她的旅途,于是她每次回农场,都会选择第二短的路径,而不象我们所习惯的那样,选择最短路。 贝茜所在的乡村有 R*(1≤R≤100,000) 条双向道路,每条路都联结了所有的 N*(1≤N≤5000) 个农场中的某两个。贝茜居住在农场1,她的朋友们居住在农场N(即贝茜每次旅行的目的地)。 贝茜选择的第二短的路径中,可以包含任何一条在最短路中出现的道路,并且,一条路可以重复走多次。当然咯,第二短路的长度必须严格大于最短路(可能有多条)的长度,但它的长度必须不大于所有除最短路外的路径的长度。

题意:n个点,r条双向边找一条严格大于最短路的边,边可以重复走
输入#1              输出:
4 4                 450
1 2 100
2 4 200
2 3 250
3 4 100


#include<bits/stdc++.h>
using namespace std;
const int N = 5e3+10;
const int M = 2e5+10;
const int INF =0x3f3f3f3f;
int e[M] , idx , ne[M] ,val[M],h[M];
int n , m ,k;
typedef long long ll;
void add(int a , int b ,int c){
   e[idx] = b;
   ne[idx] = h[a];
   val[idx] = c;
   h[a] = idx++;
}
struct node{
  int u ;
  int dis;
  bool operator < (const node &A) const{
    return dis > A.dis;
  }
};

int d1[N] , d2[N]; //d1存最短路 , d2存次短路。 因为可以重复走,所以我们不需要用st数组去重; 
void dijstra(){
   for(int i = 1 ; i<= n ; i++) {
        d1[i] = INF;d2[i] = INF ;

   }
   d1[1] = 0;
   priority_queue<node>q ;
   q.push((node){1,d1[1]});
   while(!q.empty()){
    node top = q.top();
    q.pop();
    int u = top.u;
    int dis = top.dis;
    //if(dis > d2[u]) continue;  // 这里我们发现我们传过来的距离比次短路都大了,就不需要去更新,小优化 ;
	// 当然不用也行 ,后面在判断次短路的时候可以判掉。 
    for(int i =h[u] ; i != -1  ; i= ne[i]){
        int j =e[i];
        int temp = dis + val[i];
        if(d1[j] > temp){
            d1[j] = temp;
            if(d2[j] == INF) d2[j] = temp; 
			//这地方我们要先将次短路更新一下。比如1->4的距离是3 , 1->3->4的距离是2
			//如果我们不先在更新d1的时候就更新d2的话,我们的更新情况就有可能是d1[4]=3 ,d2[4]=INF,
			//d1[3]= 1,d2[3]= INF , 再跑到4后,我们会忘回跑(可以重复跑)4->3,d2[3]=3 , d2[4]=4;
			//就更新不到原本的1->4的路径。
			//不理解就看看最后的一个样例 
            q.push((node){j,d1[j]});
        }else if(temp >d2[j] &&d2[j]==d1[j]){ //这里因为将d2[j]更新成了d1[j],所以需要判断一下d1[j]和d[2]是否相等 
        	d2[j] = temp;
        	q.push((node){j,d2[j]});
        }
         else if(d2[j] > temp && temp > d1[j] ){//temp>d2[j]就是要更新次短路,当然temp应该要大于的d1[j]; 
             d2[j] = temp;
             q.push((node){j,d2[j]});
        }
    }
   }


}
signed main()
{
    scanf("%d%d",&n,&m);
    memset(h , -1 ,sizeof h);
    for(int i = 1; i <= m ; i++){
        int a , b ,c;
        scanf("%d%d%d",&a,&b,&c);
        add(a,b,c);
        add(b,a,c);
    }
    dijstra();
    printf("%d\n",d2[n]);
}
/*这个样例应该为21 , 一般题解会是28 
5 5 
1 2 5 
2 3 5 
3 4 4
4 5 6
1 5 21
*/
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值