1003 Emergency (25分)(迪杰斯特拉算法的小变形)

问题:要求求出长度和最短路径长度相同的路径条数,和走这些路径时能聚集的人的最大数目。做这道题暴露出来一个问题:学知识过于死板,图论方面的知识还是只停留在会板子的阶段。一定要多想,多总结。

本题解法:涉及到了求最短路问题,自然能联想到用dijkstra算法,但本题要求的是长度等于最短长度的路径条数和最大人数,另设两个数组,记录最短路径条数和最大人数,并对原始dijkstra算法做小小的变形即可顺利AC

核心代码,松弛最短路时做出小小改变

for(int j=0;j<n;j++){
			if(!vis[j]&&dis[flag]+mp[flag][j]<dis[j]){
				dis[j]=dis[flag]+mp[flag][j];
				w[j]=w[flag]+weight[j];
				routes[j]=routes[flag];
			} else if(!vis[j]&&dis[flag]+mp[flag][j]==dis[j]){
				routes[j]+=routes[flag];//!!!!!!
				w[j]=max(w[j],w[flag]+weight[j]);
			}
		}

其中,w数组中保存的时最大的人数,routes数组中保存的时最短路的条数,weight数组中保存的是该站的人数

解读:当flag可以松弛点j时,证明原来到点j的不是最短路,所以人数和路径条数必须使其等于w[flag]和routes[flag];当不能松弛但是两条路径长度正好相同时,证明路径条数增多了,此时必须使得routes[j]=routes[j]+routes[flag],同时因为要求的是最大的人数,所以w[j]=max(w[j],w[flag]+weight[j])

AC代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=505;
const int INF=0x3f3f3f3f;
int mp[maxn][maxn],dis[maxn],vis[maxn],routes[maxn],weight[maxn],w[maxn];
int n,m,c1,c2;
void init() {
	for(int i=0; i<n; i++) {
		for(int j=0; j<n; j++) {
			if(i==j) mp[i][j]=0;
			else mp[i][j]=INF;
		}
	}
}
void dijkstra(int st){
	for(int i=0;i<n;i++){
		dis[i]=mp[st][i];
		w[i]=weight[i];
	}
	for(int i=0;i<n;i++){
		int minn=INF,flag=-1;
		for(int j=0;j<n;j++){
			if(!vis[j]&&dis[j]<minn){
				minn=dis[j];
				flag=j;
			}
		}
		if(flag==-1) break;
		vis[flag]=1;
		for(int j=0;j<n;j++){
			if(!vis[j]&&dis[flag]+mp[flag][j]<dis[j]){
				dis[j]=dis[flag]+mp[flag][j];
				w[j]=w[flag]+weight[j];
				routes[j]=routes[flag];
			} else if(!vis[j]&&dis[flag]+mp[flag][j]==dis[j]){
				routes[j]+=routes[flag];//!!!!!!
				w[j]=max(w[j],w[flag]+weight[j]);
			}
		}
	}
}
int main(){
	int a,b,c;
	cin>>n>>m>>c1>>c2;
	init();
	for(int i=0;i<n;i++){
		cin>>weight[i];
	}
	for(int i=0;i<m;i++){
		cin>>a>>b>>c;
		mp[a][b]=mp[b][a]=mp[a][b]<c?mp[a][b]:c;
	}
	routes[c1]=1;
	dijkstra(c1);
	printf("%d %d\n",routes[c2],w[c2]);
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值