L2-001 紧急救援 (25分)

L2-001 紧急救援 (25分)

个人wa点:求最短路径的条数(有多少条最短路径),以及能够召集的最多的救援队数量输出最多召集的路径

#include<iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <set>
#include <map>
#include <functional>
#include <ctime>
#include <iomanip>
#include <sstream>
#include <algorithm>
#define ll long long
#define PI acos(-1)
#define mes(x,y) memset(x,y,sizeof(x))
#define lp pair<ll, ll>
#define FAST_IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
const ll inf = 5e9 + 30;
ll n, m, i, j, k, t, flag, x, y, z;
string s1, s2, s;
ll gram[510][510],value[510],father[510],sumvalue[510],minlen[510],step[510],f[510];
//相互之间的距离,每个的权值,这个点的上一级,总权值,最短路径长度,开始位置到此处的要经过的点的个数,此点是否已走过
void Dijkstra(ll begin) {
	fill(minlen,minlen+n,inf); mes(sumvalue, 0); mes(step, 0); mes(f, 1);
	minlen[begin] = 0;	sumvalue[begin] = value[begin];	step[begin] = 1;
	for (i = 0; i < n; i++) {
		ll now = -1, minn = inf;
		for (j = 0; j < n; j++) {
			if (f[j] && minlen[j] < minn) {
				minn = minlen[j]; now = j;
			}
		}
	//	cout << endl << now << endl;
		if (now == -1)break;
		f[now] = 0;
		for (j = 0; j < n; j++) {
			if (f[j] == 0 || gram[now][j] == inf)continue;
			//cout << j << ":" << endl;
			//cout << minlen[now] << "+" << gram[now][j] << " " << minlen[j] << endl;
			if (minlen[now] + gram[now][j] < minlen[j]) {
				minlen[j] = minlen[now] + gram[now][j];
				sumvalue[j] = sumvalue[now] + value[j];
				father[j] = now; step[j] = step[now];
				//cout << 1 << " " << step[j] << endl;
			}
			else if (minlen[now] + gram[now][j] == minlen[j]) {
				//cout << sumvalue[j] << " " << sumvalue[now] << "+" << value[j] << endl;
				if (sumvalue[j] < sumvalue[now] + value[j]) {
					sumvalue[j] = sumvalue[now] + value[j];
					father[j] = now;
				}
				step[j] += step[now];
				//cout << 2 << " " << step[j] << endl;
			}
			//cout << minlen[j] << ":" << sumvalue[j] << endl << endl;
		}
	}
}
void finfather(ll begin,ll mid) {
	if (begin==mid) {
		cout << begin;
		return;
	}
	finfather(begin, father[mid]);
	cout<<" " << mid;
}
int main() {
	FAST_IO; ll a, b;
	while (cin >> n >> m >> a >> b) {
		fill(gram[0], gram[0] + 510 * 510, inf);
		//cout << gram[0][0] << endl;
		for (i = 0; i < n; i++)cin >> value[i];
		for (i = 0; i < m; i++) {
			cin >> x >> y >> z;
			gram[x][y] = gram[y][x] = z;
		}
		//cout << gram[1][2] << endl;
		Dijkstra(a);
		cout << step[b] << " " << sumvalue[b] << endl;
		finfather(a, b); cout << endl;
	}
}

教学版(应该只有我自己能看懂)

#include<iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <set>
#include <map>
#include <functional>
#include <ctime>
#include <iomanip>
#include <sstream>
#include <algorithm>
#define ll long long
#define PI acos(-1)
#define mes(x,y) memset(x,y,sizeof(x))
#define lp pair<ll, ll>
#define FAST_IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
const ll inf = 5e9 + 30;
ll n, m, i, j, k, t, flag, x, y, z;
string s1, s2, s;
struct node {
	ll father;
	//此点的父亲节点(一开始点为最大辈的点)
	
	ll value;
	//开始点一直到此点的最大权值
	
	ll len;
	//开始点到此点的最短路径
	
	ll step;
	//开始点到此点所有最短路径有多少条
	
}point[510];

ll gram[510][510];
//相互之间的距离

ll value[510];
//每个点的权值

ll f[510];
//判断此点此点是否已无到它的最短路径

void Dijkstra(ll begin,ll end) {
	for (i = 0; i < 510; i++) {
		point[i].len = inf;
		point[i].step = point[i].father = point[i].value = 0;
	}//赋予默认值

	point[begin].len = 0;
	//并未开始出发,因此最一开始的长度为0
	
	point[begin].value = value[begin]; 
	//权值为此点的权值
	
	point[begin].step = 1;
	//开始点只有一条路径到达它自己
	
	for (i = 0; i <n; i++) {
		ll now = -1, minn = inf;
		for (j = 0; j < n; j++) 
			if (!f[j] && point[j].len < minn) 
				minn = point[j].len,now = j;
		//找到开始点到now最短的那一条路径

		if (now == end)break;
		//如果now到end点已经是最短路径了,那么接下来,
		//1.end点不会再成为最后末点出现
		//2.后面也不会出现以后面的路径为跳板的到end点的最短路径
		
		f[now] = 1;
		//代表从此刻开始now不在作为末点出现

		for (j = 0; j < n; j++) {
		
			if (f[j]  || gram[now][j] == inf)continue;
			//确保此点未被走过并且这now和j两点之间有路
			
			if (point[now].len + gram[now][j] < point[j].len) {
				//如果开始到now的距离加上now到j的距离小于原本的路径
				
				point[j].len = point[now].len + gram[now][j];
				//即修改此点到开始的距离
				
				point[j].value = point[now].value + value[j];
				//并修改权值
				
				point[j].father = now;
				//将此点列入最后输出最大权值路径
				
				point[j].step = point[now].step;
				//采用dp,有几种路径到now,就有几种路径可以从now到j
				//由于路径长度有所改变,那么到j点的路径需要覆盖。
			}
			else if (point[now].len + gram[now][j] == point[j].len) {
				//如果开始到now的距离加上now到j的距离等于原本的路径
				
				if (point[now].value + value[j] > point[j].value) {
					//查看权值比现在的路径上的权值小
					
					point[j].value = point[now].value + value[j];
					//修改权值
					
					point[j].father = now;
					//以及修改此点未当前路径上的点
				}
				point[j].step += point[now].step;
				//采用dp,有几种路径到now,就有几种路径可以从now到j
				//由于路径长度未有所改变
				//那么到now点的那几条路径属于是最短路径那么到j点的路径需要累加起来。
				
			}
		}
	}
}
void finfather(ll begin, ll mid) {
	if (begin == mid) {
		cout << begin;
		return;
		//先输出开始点
	}
	finfather(begin, point[mid].father);
	cout << " " << mid;
	//依次输出剩下的点
}
int main() {
	FAST_IO; ll a, b;
	while (cin >> n >> m >> a >> b) {
		fill(gram[0], gram[0] + 510 * 510, inf);
		//第一次接触fill,记录一下
		for (i = 0; i < n; i++)cin >> value[i];
		for (i = 0; i < m; i++) {
			cin >> x >> y >> z;
			gram[x][y] = gram[y][x] = z;
		}
		//赋值,路径是双向的
		Dijkstra(a,b);
		cout << point[b].step << " " << point[b].value << endl;
		finfather(a, b); cout << endl;
	}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GUESSERR

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值