1003 Emergency (25 分)

跟着柳婼学姐学习的笔记ヾ(≧▽≦*)o


原题目: 1003 Emergency (25 分).

题意

一张地图,城市间由道路连接,并标有每个城市的救援队数量以及每条路的长度。
给出城市数N(≤500,编号0~N-1),道路数M,所在城市C1和要救援的城市C2。接着N个整数给出每个城市的救援队数量,接着M行给出城市对和距离(C1到C2至少有一条路)。
① 求C1到C2的最短路径数量,
② 最短路径上的救援队最多数量。

分析

  1. 最短路径问题(单源且正值)——Dijkstra算法。
  2. 在优化部分,增加:① 更新最短路径数量,② 更新点权值(城市救援队数量)。

CODE

#include <iostream>
using namespace std;
const int maxv = 510;
const int inf = 1000000000;
int n, m, c1, c2;
int G[maxv][maxv], weight[maxv];  //图,救援队数量
int dis[maxv], num[maxv], w[maxv];  //最短路径长度,最短路径数量,最大救援队数量(均从c1开始到各顶点)
bool vis[maxv];  //标记访问

void Dijkstra(int c1);
int main()
{
    cin >> n >> m >> c1 >> c2;
    for ( int i=0; i<n; i++ )
        cin >> weight[i];
    //建图
    fill(G[0], G[0]+maxv*maxv, inf);  //初始化
    for ( int i=0; i<m; i++ ){
        int a, b, c;
        cin >> a >> b >> c;
        G[a][b] = G[b][a] = c;
    }
    Dijkstra(c1);
    printf("%d %d", num[c2], w[c2]);
    
    return 0;
}
void Dijkstra(int c1){  //起点为c1
    //初始化
    fill(dis, dis+maxv, inf);
    dis[c1] = 0;
    w[c1] = weight[c1];  //救援队
    num[c1] = 1;  //c1到c1的最短路径数量
    //遍历所有城市
    for ( int i=0; i<n; i++ ){
        //找到u使d[u]最小
        int u = -1, mindis = inf;
        for ( int j=0; j<n; j++ ){
            if ( vis[j]==false && dis[j]<mindis ){
                u = j;
                mindis = dis[j];
            }
        }
        //没找到u
        if ( u==-1 ) return;
        //找到u
        vis[u] = true;  //标记访问
        //以u为中介点遍历其邻接点v,优化d[v]
        for ( int v=0; v<n; v++ ){
            if ( vis[v]==false && G[u][v]!=inf ){
                if ( dis[u]+G[u][v]<dis[v] ){
                    dis[v] = dis[u] + G[u][v];  //优化距离
                    num[v] = num[u];  //起点到v的最短路径数量与到u的数量相同
                    w[v] = w[u] + weight[v];  //更新能到达v的救援队数量
                }
                else if ( dis[u]+G[u][v]==dis[v] ){  //多条最短路径
                    num[v] += num[u];  //从原来的路径到v + 从新路径到v
                    if ( w[u]+weight[v]>w[v] )
                        w[v] = w[u] + weight[v];  //要求救援队数量最多
                }
            }
        }
    }
}

CODE V2——BF解法

#include <iostream>
#include <vector>
#include <set>
#include <algorithm>
using namespace std;
const int maxv = 510;
const int inf = 1000000000;
struct node{
	int v, dis;  //邻接点,邻接边的边权
};
vector<node> Adj[maxv];  //邻接表
int n, m, st, ed,weight[maxv];  //st和ed分别为起点和终点,weight[]记录点权
int d[maxv], w[maxv], num[maxv];  //w[]记录最大点权之和,num[]记录最短路径条数
set<int> pre[maxv];  //前驱

void Bellman(int s){
	//初始化
	fill(d, d+maxv, inf);
	d[s] = 0;
	w[s] = weight[s];
	num[s] = 1;  //s到s有1条路径
	//循环n-1趟,生成d[]
	for ( int i=0; i<n-1; i++ ){
		for ( int u=0; u<n; u++ ){  //遍历每个顶点
			for ( int j=0; j<Adj[u].size(); j++ ){
				int v = Adj[u][j].v;  //u的邻接点
				int dis = Adj[u][j].dis;  //邻接边的边权
				if ( d[u]+dis<d[v] ){
					d[v] = d[u] + dis;
					w[v] = w[u] + weight[v];
					num[v] = num[u];   //覆盖
					pre[v].clear();
					pre[v].insert(u);
				}
				else if ( d[u]+dis==d[v] ){  //不止一条最短路径
					if ( w[u]+weight[v]>w[v] ){  //点权更大时
						w[v] = w[u] + weight[v];
					}
					pre[v].insert(u);
					//重新统计num[v]
					num[v] = 0;
					for ( auto it=pre[v].begin(); it!=pre[v].end(); it++ ){
						num[v] += num[*it];
					}
				}
			}
		}
	}
}
int main()
{
	cin >> n >> m >> st >> ed;
	for ( int i=0; i<n; i++ )
		cin >> weight[i];
	int u, v, wt;
	for ( int i=0; i<m; i++ ){
		cin >> u >> v >> wt;
		Adj[u].push_back(node{v,wt});
		Adf[v].push_back(node{u,wt});
	}
	Bellman(st);
	printf("%d %d", num[ed], w[ed]);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值