【spfa变形】:出行

【题目描述】

某人打算外出旅游,他从起点城市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
*/


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值