uva 10269(最短路径)

题意:有n个村庄和m个城堡,村庄编号从1开始,城堡编号从n+1开始,一个人带着公主要从城堡n+m到村庄1,他还有一个魔法鞋可以有cnt次的使用机会可以让人能不花费时间走最多l,人只能在路上没有城堡的时候使用这个魔法鞋,问最少花费多少时间能到达村庄1。

题解:最短路径问题,用spfa算法,先用floyd将地点i到j的最短距离求出(不经过城堡),然后用f[i][j]表示到达结点i还剩j次穿魔法鞋机会的花费时间,与普通的spfa不同的是加了一个判断:f[u][t1] > f[i][t1-1],意味着从u到i用一次魔法鞋如果可以减短时间就用掉,并且如果不再队列中就加到队尾。

#include <stdio.h>
#include <string.h>
#include <queue>
using namespace std;
const int N = 150;
const int INF = 0x3f3f3f3f;
int f[N][N], g[N][N], vis[N][N];
int t, n, m, p, l, cnt;

void spfa() {
	int st = n + m;
	queue<int> q1;
	queue<int> q2;
	memset(vis, 0, sizeof(vis));
	memset(f, INF, sizeof(f));
	for (int i = 0; i <= cnt; i++)
		f[m + n][i] = 0;
	q1.push(st);
	q2.push(cnt);
	while (!q1.empty()) {
		int u = q1.front();
		q1.pop();
		int t1 = q2.front();
		q2.pop();
		vis[u][t1] = 0;
		for (int i = 1; i <= n + m; i++) {
			if (f[i][t1] > f[u][t1] + g[u][i]) {
				f[i][t1] = f[u][t1] + g[u][i];
				if (!vis[i][t1]) {
					vis[i][t1] = 1;
					q1.push(i);
					q2.push(t1);
				}
			}
			if (t1 > 0 && g[u][i] <= l && f[u][t1] < f[i][t1 - 1]) {
				f[i][t1 - 1] = f[u][t1];
				if (!vis[i][t1 - 1]) {
					vis[i][t1 - 1] = 1;
					q1.push(i);
					q2.push(t1 - 1);
				}
			}
		}
	}

}

void floyd() {
	for (int k = 1; k <= n; k++)
		for (int i = 1; i <= n + m; i++)
			for (int j = 1; j <= n + m; j++)
				if (g[i][j] > g[i][k] + g[k][j])
					g[i][j] = g[i][k] + g[k][j];
}

int main() {
	scanf("%d", &t);
	while (t--) {
		scanf("%d%d%d%d%d", &n, &m, &p, &l, &cnt);
		memset(g, INF, sizeof(g));
		int u, v, w;
		for (int i = 0; i < p; i++) {
			scanf("%d%d%d", &u, &v, &w);
			g[u][v] = g[v][u] = w;
		}
		floyd();
		spfa();
		int minn = INF;
		for (int i = 0; i <= cnt; i++)
			if (minn > f[1][i])
				minn = f[1][i];
		printf("%d\n", minn);
	}
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值