题目链接
题目描述
某华大学小飞中奖了!!!奖品是一张免费飞机票,唯一遗憾的是,这张飞机票有限定区间,需要从k个区间中选择其一。小飞打算高高兴兴的出去玩啦,但是,从s地出发,去往e地,可能没有直达的飞机票,可能需要转机(所有飞机线路都是无向的),小飞毕竟是个学生党,出去玩首先得考虑省钱,所以,小飞遇到麻烦了,请帮小飞计算最便宜的一条路线,小飞会很感激你的。
输入描述:
第一行为三个整数n,s,e,n表示n个不同城市的飞机场,s为出发点,e为目的地。(1<=n<=1000, 1<=s,e<=n) 第二行为一个整数m,表示m条普通飞机线路,接下来的m行描述每条线路,每行包含三个整数a、b、c,a、b代表普通飞机线路两端,c表示价格。(1<=m<=1000, 1<=a,b<=n, 1<=c<=1000) 接下来的一行为一个整数k,表示k个免费机票的航线区间, 然后k行来描述每条免费航线,每行两个整数a’、b’, 分别代表免费航线两端。(1<=k<=1000, 1<=a’,b’<=n)
输出描述:
每个测试数据有两行输出,第一行为是否使用免费飞机票,是则输出“Yes”,否则输出“No”。第二行输出总共花费。
示例1
输入
4 1 4 3 1 2 1 1 3 2 2 4 3 1 3 4
输出
Yes 2
示例2
输入
7 1 7 5 1 4 1 1 5 2 1 7 10 4 7 8 5 7 5 2 2 4 6 7
输出
No 7
题意:就是一个有n个点的图,里面有m条边,现在可以把给出的K条边其中的一条路径话费变成0,现在要求在这种条件下从s到e的最小话费,并且判断最小花费是否走了k条路中的一条。.
题解:其实题理解很简单,就是一个最短路,但是如果一个一个判断k条路那条赋值为0,话费最优的话,肯定会超时。所以这里就要求单边最短路。首先那两个数组记录起点与终点到每个点的最小花费。然后就去遍历k条路的每一条,例如比如说(u,v)之间的权值可赋值为0,就比较开始跑的最短路s到e的花费和min(dis1[u]+dis2[v],dis1[v]+dis2[u]);的花费那个小,(这个式子表示s到u的花费+e到v的花费,正好减去了u,v的花费,取min很容易理解)。然后这样遍历每一条边,要是新的花费比原来的小,说明走这条路更优,一直取最小值就是答案,细节看代码。
#include <iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<cmath>
#include<stack>
#include<string>
//#include<unordered_map>
//#include<unordered_set>
const int maxn=1e3+10;
const int mod=20190414;
const int inf=1e9;
const long long onf=1e18;
#define me(a,b) memset(a,b,sizeof(a))
#define lowbit(x) x&(-x)
#define mid l+(r-l)/2
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define PI 3.14159265358979323846
int dir[4][2]= {0,-1,-1,0,0,1,1,0};
int dx[]= {-2,-2,-1,-1,1,1,2,2};
int dy[]= {-1,1,-2,2,-2,2,-1,1};
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
int maps[maxn][maxn];
int dis1[maxn],dis2[maxn];
int n;
void DIJ(int s,int *dis)
{
bool vis[maxn];me(vis,0);
fill(dis,dis+maxn,inf);
dis[s]=0;
for(int i=1; i<=n; i++)
{
int Min=inf,u=-1;
for(int j=1; j<=n; j++)
if(!vis[j]&&(u==-1||Min>dis[j]))
u=j,Min=dis[j];
if(u==-1)
return ;
vis[u]=1;
for(int j=1; j<=n; j++)
if(!vis[j]&&maps[u][j]+dis[u]<dis[j])
dis[j]=dis[u]+maps[u][j];
}
}
int main()
{
int s,e,m;
scanf("%d%d%d",&n,&s,&e);
scanf("%d",&m);
fill(maps[0],maps[0]+maxn*maxn,inf);
for(int i=1;i<=n;i++)
maps[i][i]=0;
for(int i=0; i<m; i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
maps[u][v]=maps[v][u]=w;
}
int k;
bool flag=0;
DIJ(s,dis1),DIJ(e,dis2);///dis1保存s到每点的最短距离,dis2保存e到每点最短距离。
int Min=dis1[e];///保存最初的花费,方便后面做比较
scanf("%d",&k);
for(int i=0; i<k; i++)
{
int u,v;
scanf("%d%d",&u,&v);
int temp=min(dis1[u]+dis2[v],dis1[v]+dis2[u]);///比较当前路权值为0时,答案会不会更优
if(temp<Min)///一直找最优解
{
flag=1;
Min=temp;
}
}
if(flag)
puts("Yes");
else
puts("No");
printf("%d\n",Min);
return 0;
}