BZOJ 2763: [JLOI2011]飞行路线

本文探讨了如何使用SPFA算法解决旅行中的成本优化问题,具体是在特定条件下找到从起点到终点的最低花费路径,考虑到免费乘坐特定数量航班的优惠。

Description

Alice和Bob现在要乘飞机旅行,他们选择了一家相对便宜的航空公司。该航空公司一共在n个城市设有业务,设这些城市分别标记为0到n-1,一共有m种航线,每种航线连接两个城市,并且航线有一定的价格。Alice和Bob现在要从一个城市沿着航线到达另一个城市,途中可以进行转机。航空公司对他们这次旅行也推出优惠,他们可以免费在最多k种航线上搭乘飞机。那么Alice和Bob这次出行最少花费多少?

Input

数据的第一行有三个整数,n,m,k,分别表示城市数,航线数和免费乘坐次数。

第二行有两个整数,s,t,分别表示他们出行的起点城市编号和终点城市编号。(0<=s,t<n)

接下来有m行,每行三个整数,a,b,c,表示存在一种航线,能从城市a到达城市b,或从城市b到达城市a,价格为c。(0<=a,b<n,a与b不相等,0<=c<=1000)

 

Output

 

只有一行,包含一个整数,为最少花费。

Sample Input

5 6 1
0 4
0 1 5
1 2 5
2 3 5
3 4 5
2 3 3
0 2 100

Sample Output

8.

思路:

就是记录一下跑spfa 的时候,少走几条边时的最短距离。 

#include<bits/stdc++.h>
using namespace std;
const int M = 1e5+1000;
const int N = 2e4+100;
const int INF = 0x3f3f3f3f;
typedef pair<int,int> P;
struct node{
	int to,value,next;
}p[M];
bool inq[N][11];
int dis[N][15],head[M],cnt;
int n,m,k,s,t;
void Add(int u, int v, int w){
	p[++cnt] = {v,w,head[u]};
	head[u] = cnt;
	return;
}
void init(){
	int x,y,z;
	memset(head,-1,sizeof(head));
	cnt = -1; 
	scanf("%d%d%d",&n,&m,&k);
	scanf("%d%d",&s, &t);
	for (int i = 0; i < m; i++){
		scanf("%d%d%d",&x,&y,&z);
		Add(x,y,z);
		Add(y,x,z);
	}	
	return;
}

void spfa(){
	memset(dis,INF,sizeof(dis));
	queue<P>q;
	q.push(P(s,0));
	dis[s][0] = 0; inq[s][0] = 1;
	while(!q.empty()){
		int u = q.front().first;
		int tmp = q.front().second; q.pop(); //tmp 是少走几条路。。 
		for (int i = head[u]; ~i; i = p[i].next){  // 正常操作。 
			int v = p[i].to;
			if (dis[u][tmp] + p[i].value < dis[v][tmp]){
				dis[v][tmp] = dis[u][tmp] + p[i].value;
				if (!inq[v][tmp]){
					inq[v][tmp] = 1;
					q.push(P(v,tmp));
				}
			}
			if (dis[u][tmp] < dis[v][tmp+1] && tmp < k){ //这里就是分层的操作了。
				dis[v][tmp+1] = dis[u][tmp]; //当前点和下一个点。是不是可以少走一条边。 
				if (!inq[v][tmp+1]){
					inq[v][tmp+1] = 1;
					q.push(P(v,tmp+1));
				}
			}
		}
		inq[u][tmp] = 0;
	}
	int ans = INF;
	for (int i = 0; i <= k; i++)
		ans = min(ans,dis[t][i]);
	printf("%d\n",ans);
	return;
}


int main(){
	init();
	spfa();
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值