【题目描述】
某人打算外出旅游,他从起点城市1出发,计划到达城市n。城市之间被一些航线连通, 航线可以从任意方向飞行。由于是航空公司会员,他获得一次半价(半价以后价格只保留整数部分)机票的折扣券,使用的时机可以任意安排。
【输入】
输入第一行包含两个数n, m,表示城市数量和航线数量。
接下来的m行每行有3个数ai, bi, wi,分别表示第i条航线连接的第一个城市和第二个城市,以及航线的费用。
【输出】
输出一个整数,表示路途中花费的最小值。
【输出样例】
3 3
1 2 3
2 3 4
3 1 8
【输出样例】
4
【样例解释】
直接从 1号城市飞到3号城市并出示折扣券是最优方案
【数据规模】
对于30%的数据,n<=100,m<=100
对于50%的数据,n<=1000,m<=1500
对于所有数据,2<=n<=10000,1<=m<=100000, 1<=ai, bi<=n, wi<=10000,1<=n<=m。
保证存在一条路径可以从城市1到城市n的飞行方案。
因为题目中要求可在某条路上半价,所以在spfa中要进行部分改动。
#include<cstdio>//spfa
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=10005;
const int maxe=200005;
const int INF=0x7f7f7f;
struct edge
{
int to,next;
int value;
}e[maxe];
int n,m;
int a,b,w;
int k=0;
long long dist[maxn];
long long dist2[maxn];
int queue[maxe];
bool visit[maxn];
int tail,qhead;
int head[maxe];
int num[maxe];
void add(int u,int v,int w)
{
k++;
e[k].to=v;
e[k].value=w;
e[k].next=head[u];
head[u]=k;
}
void spfa(int s,int t)
{
memset(visit,false,sizeof(visit));
memset(dist,INF,sizeof(dist));
memset(dist2,INF,sizeof(dist2));
qhead=0;
tail=1;
queue[tail]=s;
dist[s]=0;
dist2[s]=0;
visit[s]=true;
while(qhead<tail)
{
qhead++;
int p=queue[qhead];
visit[p]=false;
int p1=head[p];
while(p1!=0)
{
bool flag=1;//记录有没有被松弛过
if(dist[e[p1].to]>dist[p]+e[p1].value)
{
dist[e[p1].to]=dist[p]+e[p1].value;
flag=0;
}
if(dist2[e[p1].to]>dist2[p]+e[p1].value)
{
dist2[e[p1].to]=dist2[p]+e[p1].value;
flag=0;
}
if(dist2[e[p1].to]>dist[p]+e[p1].value/2)
{
dist2[e[p1].to]=dist[p]+e[p1].value/2;
flag=0;
}
if(!flag&&!visit[e[p1].to])
{
tail++;
queue[tail]=e[p1].to;
visit[e[p1].to]=true;
}
p1=e[p1].next;
}
}
printf("%lld",dist2[t]);
}
int main()
{
freopen("trip.in","r",stdin);
freopen("trip.out","w",stdout);
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d %d %d",&a,&b,&w);
add(a,b,w);
add(b,a,w);
}
spfa(1,n);
return 0;
}
/*
5 6
1 4 1
1 2 11
2 3 1
3 4 2
1 5 16
2 5 4
*/