题目描述
给定一个有向带权图,其中包括 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。
题解:其实这题最简单的方法就是Floyd算法,只不过时间会超,其实这里也不难想到用Dijkstra算法,因为常用的求最短路里只有它不会超时。思路如下
此图来自dmu学长的ppt
我们假设我们要修改3和6之间的方向
既然修改了这条边,如果不从这条边走,修改就毫无意义(因为对最短的距离没有影响),故我们必定要走这条路,因为修改前方向是6-3,故修改后是3-6,这里我们假设从s点(起点)到3的最短距离为d【3】,终点t到6的最短距离为b【6】,则修改后且必须走这条路从起点到终点的最短距离为b【3】+d【6】+num(这条路的长度),相信有的同学已经知道怎么做了,我们需要以s点为起点用Dijkstra算法求到所有点的最短路,再以t点为起点求到所有点的最短路,在按照上面的公示,答案就出来了。
代码如下
c++代码
#include<iostream>
#include<queue>
#include<string.h>
#include<string>
#include<vector>
#include<map>
typedef long long ll;
using namespace std;
#define ll long long
#define maxn 100005
#define INF 2147483647000000000
#define IOS ios::sync_with_stdio(false)
struct edge
{
ll to, cost;
};
typedef pair<ll, ll> P;
ll n, m, st;
ll d[maxn],d0[maxn],d1[maxn];
bool visited[maxn];
vector<edge> G0[maxn],G1[maxn];
void dijsktra(ll s, ll V,vector<edge>G[maxn])
{
priority_queue<P, vector<P>, greater<P> > que;
for (ll i = 0; i < V; i++) d[i] = INF;
memset(visited, 0, sizeof(visited));
d[s] = 0;
que.push(P(0, s));
while (!que.empty())
{
P p = que.top();
que.pop();
ll v = p.second;
if (d[v] < p.first) continue;
for (ll i = 0; i < G[v].size(); i++)
{
edge e = G[v][i];
if (d[e.to] > d[v] + e.cost){
d[e.to] = d[v] + e.cost;
que.push(P(d[e.to], e.to));
}
}
}
}
struct node{
ll u,v,dis;
};
map<ll,node>mp;
int main()
{
IOS;
ll n,m;
cin>>n>>m;
for(int i=0;i<m;i++)
{
ll u,v,dis;
cin>>u>>v>>dis;
G0[u].push_back(edge{v,dis});
G1[v].push_back(edge{u,dis});//反向图
mp[i+1]=node{u,v,dis};
}
dijsktra(1,n+1,G0);
for(int i=1;i<=n;i++)
d0[i]=d[i];
dijsktra(n,n+1,G1);
for(int i=1;i<=n;i++)
d1[i]=d[i];
ll Q;
cin>>Q;
while(Q--)
{
ll id;
cin>>id;
node t0=mp[id];
ll dis1=d0[t0.v],dis2=d1[t0.u];
if(d0[n]>dis1+dis2+t0.dis)
cout<<"YES\n";
else
cout<<"NO\n";
}
return 0;
}
java代码
import java.io.*;
public class Main {
static int na,nb,nc,nd,m,ans;
static char[] select=new char[13];
static int arr[][];
static void dfs(int index,int a,int b,int c,int d) {
if(a>na||b>nb||c>nc||d>nd) return ;
for(int i=0;i<m;i++) {
int x=arr[i][0];
int y=arr[i][1];
if(index>x&&index>y&&select[x]!=select[y]) return;
}
if(index==13) {
if(a==na&&b==nb&&c==nc&&d==nd) {
ans++;
}
return ;
}
select[index]='a';
dfs(index+1,a+1,b,c,d);
select[index]='b';
dfs(index+1,a,b+1,c,d);
select[index]='c';
dfs(index+1,a,b,c+1,d);
select[index]='d';
dfs(index+1,a,b,c,d+1);
}
public static void main(String[] args) throws IOException {
StreamTokenizer st=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
st.nextToken();
na=(int)st.nval;
st.nextToken();
nb=(int)st.nval;
st.nextToken();
nc=(int)st.nval;
st.nextToken();
nd=(int)st.nval;
st.nextToken();
m=(int)st.nval;
arr=new int[m][2];
for(int i=0;i<m;i++) {
for(int j=0;j<2;j++) {
st.nextToken();
arr[i][j]=(int)st.nval;
}
}
dfs(1,0,0,0,0);
System.out.println(ans);
}
}