PAT A1003 Emergency (25分)【单源最短路径模板题】

今天也是为了cc,努力奋斗的一天ヾ(≧▽≦*)o

疑问

暂无

代码——Dijkstra版

#include<stdio.h>

#include<algorithm>

using namespace std;
 
//最大的点的数量 
const int MAXV = 1010;
//定义不可达时的距离 
const int INF = 1000000000;

//输入节点数 
int n; 
//源点s
int s;
//终点t
int t; 
//无向图G
int G[MAXV][MAXV];
//标记是否访问数组
bool vis[MAXV] = {false};
//单源最短路径数组
int d[MAXV];
//单源最短路径条数数组
int num[MAXV] = {0};
//救援数rescue数组
int r[MAXV]={0}; 
//单源最短路径最大救援数数组
int maxr[MAXV]={0};

//单源最短路径Dijkstra算法
void Dijkstra(){
	//1.初始化操作 
	//首先,数组d[MAXV]中的单源最短路径设置为INF 
	fill(d,d+MAXV,INF);
	
	//将起点s到自己的距离设置为0
	d[s] = 0;
	
	//将起点s的路径数设置为1
	num[s] = 1;
	
	//将起点s的单源最短路径最大救援数设置为它的初始值 
	maxr[s] = r[s]; 
	
	for(int i=0;i<n;i++){
		
		//2.求最近的点 
		int u = -1;
		int MIN = INF;
		
		for(int j=0;j<n;j++){
			if(vis[j] == false && d[j] != INF && d[j] < MIN){
				u = j;
				MIN = d[j];
			}
		}
		
		//设置最近的点已经被访问 
		vis[u] = true;
		
		//如果u还是-1,说明存在不相连的点,则退出循环 
		if(u == -1){
			return;
		} 
		
		//3.对d[v]进行更新
		for(int v=0;v<n;v++){
			if(vis[v] == false && G[u][v] != INF){
				if(G[u][v] + d[u] < d[v]){
					d[v] = G[u][v] + d[u];
					num[v] = num[u];
					maxr[v] = r[v] + maxr[u];
				}else if(G[u][v] + d[u] == d[v]){
					num[v] += num[u];
					if(maxr[v] < r[v] + maxr[u]){
						maxr[v] = r[v] + maxr[u];
					}
				}
			}
		} 
	}
	
	printf("%d %d",num[t],maxr[t]);
} 

 
int main(){
	//numberOfRoads
	int nor;
	scanf("%d %d %d %d",&n,&nor,&s,&t);
	
	
	//初始化图G
	fill(G[0],G[0]+MAXV*MAXV,INF);
	 
	for(int i=0;i<n;i++){
		scanf("%d",&r[i]);
	}
	
	for(int i=0;i<nor;i++){
		int a,b,c;
		scanf("%d %d %d",&a,&b,&c);
		G[a][b] = c;
		G[b][a] = c;
	}	
	
	Dijkstra();

	return 0;
}

代码——Bellman-Ford版

#include<stdio.h>
#include<vector>
#include<set>
#include<algorithm>
using namespace std;

const int MAXV = 510;
const int INF = 1000000000;

struct Node{
	int v;
	int dis;
};

//顶点的数量 
int n;
//边的数量 
int m;
//起点
int s;
//终点
int t;
//邻接表
vector<Node> Adj[MAXV];
//存放最短路径的数组
int d[MAXV];
//存放每个点的权重的数组
int weight[MAXV]; 
//存放最大权重的数组 
int w[MAXV];
//存放前驱节点
set<int> pre[MAXV]; 
//存放最短路径的个数 
int num[MAXV]; 

bool Bellman(int s){
	fill(d,d+MAXV,INF);
	fill(w,w+MAXV,0);
	fill(num,num+MAXV,0);
	
	d[s] = 0;
	w[s] = weight[s];
	num[s] = 1;
	
	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;
				int dis = Adj[u][j].dis;
				if(d[u] + dis < d[v]){
					d[v] = d[u] + dis;
					pre[v].clear();
					pre[v].insert(u);
					num[v] = num[u];
					w[v] = w[u] + weight[v];
				}else if(d[u] + dis == d[v]){
					pre[v].insert(u);
					num[v] = 0;
					for(set<int>::iterator it = pre[v].begin();it != pre[v].end();it++){
						num[v] += num[*(it)];
					}
					if(w[u] + weight[v] > w[v]){
						w[v] = w[u] + weight[v];
					}
				}	
			}
		}
	}
	
	for(int u=0;u<n;u++){
		for(int j=0;j<Adj[u].size();j++){
			int v = Adj[u][j].v;
			int dis = Adj[u][j].dis;
			if(d[u] + dis < d[v]){
				return false;
			} 
		}
	}
	
	printf("%d %d",num[t],w[t]);
	return true;
}
 
int main(){
	scanf("%d %d %d %d",&n,&m,&s,&t);
	
	for(int i=0;i<n;i++){
		scanf("%d",&weight[i]);
	}
	
	for(int i=0;i<m;i++){
		int x,y,z;
		scanf("%d %d %d",&x,&y,&z);
		Node n1;
		Node n2;
		n1.v = x;
		n1.dis = z;
		n2.v = y;
		n2.dis = z;
		
		Adj[x].push_back(n2);
		Adj[y].push_back(n1);
	}
	
	Bellman(s);
	
	return 0;
} 

反思

  1. 忘记对邻接矩阵G[MAXV][MAXV]进行初始化了,然后。。。发现了也不知道该怎么初始化,2333,《算法笔记》上对二维数组的初始化,我受教了:fill(G[0],G[0]+MAXV*MAXV,INF)
  2. 感觉这个Dijkstra其实还好,只要理解了伪代码,自己写起来还是比较容易的;
  3. 这道题目比较综合,不是“裸”的Dijkstra,加入了点权最短路径数量,比较综合,值得一做,做一道题,训练三个点,爽呀~~~~
  4. 集合的遍历,可以使用迭代器进行,我又忘记了,呜呜呜:
    for(set<int>::iterator it = pre[v].begin();it != pre[v].end();it++){
    	num[v] += *(it);
    }
    
  5. 集合set使用迭代器遍历时,不能使用it < pre[v].end(),只能使用it != pre[v].end
  6. 集合set清空操作为clear()
  7. 结构体的构造函数:
struct Node{
	int v,dis;
	Node(int _v,int _dis) : v(_v),dis(_dis) {}
}

参考文档

算法笔记

二刷代码

题中没有说两个点之间只存在一条公路,所以用邻接表会好一些,而且大多数情况下,我们都是用邻接表多一些。

//非常综合的一道题目 
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn = 550;
const int inf = 0x3fffffff;
 
struct node{
	int v;
	int dis;
	node(){}
	node(int _v,int _dis){
		v=_v;
		dis=_dis;
	}
};

int d[maxn];
int c[maxn];
bool vis[maxn];
int p[maxn]; 
int num[maxn];
vector<node> adj[maxn];
int n,m,s,t;

void Dijkstra(int s,int t){
	//初始化
	fill(vis,vis+maxn,false);
	fill(d,d+maxn,inf);
	fill(num,num+maxn,0);
	fill(p,p+maxn,0);
	d[s]=0;
	num[s]=1;
	p[s]=c[s];//初始化价值
	
	for(int i=0;i<n;i++){//循环n次~
		int u=-1;
		int MIN=inf;
		for(int i=0;i<n;i++){
			if(vis[i]==false){
				if(d[i]<MIN){
					u=i;
					MIN=d[u];
				}
			}
		}	 
		vis[u]=true;
		if(u==t){
			printf("%d %d",num[t],p[t]);
			return;
		}
		
		for(int j=0;j<adj[u].size();j++){
			node curNode = adj[u][j];
			int v = curNode.v;
			int dis = curNode.dis;
			if(vis[v]==false){
				if(d[u]+dis<d[v]){
					d[v]=d[u]+dis;
					num[v]=num[u];
					p[v]=p[u]+c[v];
				}else if(d[u]+dis==d[v]&&p[u]+c[v]>p[v]){
					num[v]+=num[u];
					p[v]=p[u]+c[v];	//可以更新				
				}else if(d[u]+dis==d[v]){ //只是长度相等 
					num[v]+=num[u]; 
				}
			}
		}
	} 
	return; 
}

int main(){
	//freopen("input.txt","r",stdin);
	scanf("%d %d %d %d",&n,&m,&s,&t);
	for(int i=0;i<n;i++){
		scanf("%d",&c[i]);
	}
	for(int i=0;i<m;i++){
		int u,v,dis;
		scanf("%d %d %d",&u,&v,&dis);
		adj[u].push_back(node(v,dis));
		adj[v].push_back(node(u,dis));
	}
	
	Dijkstra(s,t);
	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值