最短路变短了题解

链接:登录—专业IT笔试面试备考平台_牛客网
来源:牛客网

题号:NC202496
时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

        给定一个有向带权图,其中包括 n个城市,城市编号从1 到n,有向边的编号从 1 到 m,现在有一个人位于城市 1,并且想要到城市n旅游。现在政府正在决定将一条道路反向,这个人想知道在某一指定道路反向的情况到达城市n最短路径长度会不会变短。

        保证开始给定的图从城市1可以到达城市n,若边反向后城市1不能到达城市n,我们视为最短路径长度没有变短。

输入描述:

第一行包括两个整数n,m(1≤n≤100000,1≤m≤200000)

接下来m行每行三个整数u,v,c (1≤u,v≤n, 1≤c≤10^9),分别代表一条有向边的起点,终点和边权。保证没有自环。

接下来一行一个整数q(1≤q≤200000),代表查询组数,查询之间是独立的。

接下来q行每行一个整数x(1≤x≤m),代表询问将第x条边反向后到达城市n的最短路长度会不会变短。

输出描述:

共q行,如果最短路变短输出YES,否则输出NO。

示例1

输入

3 4 
1 2 100 
2 3 100 
3 1 100 
2 1 1 
2 
1
4

输出

NO
YES

说明

第一条边反向后从点1无法到达点3,所以输出NO。

第四条边反向后从点1到点3的最短路长度从200减少到101,所以输出YES

分析

 

 

代码实现

#include<bits/stdc++.h>
using namespace std;
long long n,m,u,v,c,q,x;
long long cnt[200009],sum;
long long dist[200009],path[200009],g[200009],l,r;
bool flag[100009];
struct Node{
	long long id;
	long long dist;
	Node(){
	}
	Node(long long i,long long d){
		id=i;
		dist=d;
	}
	friend bool operator <(Node a,Node b){
		return a.dist>b.dist;
	}
};
struct inf{
	long long x;
	long long y;
	long long w;
};
inf edg[200009];
vector<Node>vt[200009],vt2[200009];
void Dijkstra2(int sid){
	priority_queue<Node>pque;
	memset(flag,false,sizeof(flag));
	memset(dist,0x3f,sizeof(dist));
	dist[sid]=0;
	pque.push(Node(sid,dist[sid]));
	while(pque.size()){
		Node from=pque.top();
		pque.pop();
		if(flag[from.id]){
			continue;
		}
		flag[from.id]=true;
		for(auto to:vt2[from.id]){
			if(!flag[to.id]&&dist[to.id]>dist[from.id]+to.dist){
				dist[to.id]=dist[from.id]+to.dist;
				pque.push(Node(to.id,dist[to.id]));
			}
		}
	}
}
void Dijkstra(int sid){
	priority_queue<Node>pque;
	memset(flag,false,sizeof(flag));
	memset(dist,0x3f,sizeof(dist));
	dist[sid]=0;
	pque.push(Node(sid,dist[sid]));
	while(pque.size()){
		Node from=pque.top();
		pque.pop();
		if(flag[from.id]){
			continue;
		}
		flag[from.id]=true;
		for(auto to:vt[from.id]){
			if(!flag[to.id]&&dist[to.id]>dist[from.id]+to.dist){
				dist[to.id]=dist[from.id]+to.dist;
				pque.push(Node(to.id,dist[to.id]));
			}
		}
	}
}
int main(){
    scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++){
		scanf("%d%d%d",&u,&v,&c);;
		vt[u].push_back(Node(v,c));
		vt2[v].push_back(Node(u,c));
		edg[i].x=u;
		edg[i].y=v;
		edg[i].w=c;
	}
	scanf("%d",&q);
	Dijkstra(1);
	for(int i=1;i<=n;i++){
		cnt[i]=dist[i];
	}
	Dijkstra2(n);
	for(int i=1;i<=n;i++){
		g[i]=dist[i];
	}
	for(int i=1;i<=q;i++){
		scanf("%d",&x);
		l=cnt[edg[x].y]+edg[x].w;//edg前面的路径长度 
		r=g[edg[x].x];//edg后面的路径长度 
		sum=l+r;//总的路径长度	
		if(sum>cnt[n]){
			printf("NO\n");
		}else{
			printf("YES\n");
		}
	}
	return 0; 
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值