PAT甲级1003 Emergency (25分)
题目:
解题思路:由于是第一次接触到图的问题,所以重温了一下数据结构的Dijkstra算法吧,不太会写,在搜集了各种资料之后终于AC,所以做了详细的注释,可能下次遇到Dijkstra会好受一点吧
附上AC代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxv = 510;//最大顶点数
const int inf = 1000000000;//无穷大
//n为顶点数,m为边数,st和ed分别为起点和终点
//G为邻接矩阵,weight为点权
//d[]记录最短距离,w[]记录最大点权之和,num[]记录最短路径条数
int n,m,st,ed,G[maxv][maxv],weight[maxv];
int d[maxv],w[maxv],num[maxv];
bool vis[maxv]={
false};//vis[i]==true表示顶点i已访问,初始均为false
void Dijkstra(int s){
//s为起点
fill(d,d+maxv,inf);//将最短距离填充为inf
memset(num,0, sizeof(num));//把num数组(最短路径条数)也填满
memset(w,0, sizeof(w));//把w数组也填满
d[s]=0;//从s到s的最短距离当然是0啦,因为s是起点鸭,相当于赋初值
w[s]=weight[s];//w[]记录最大点权之和,weight[s]是起点处的点权,w[s](s的最大点权之和)必然是weight[s]啦
num[s]=1;//num[s]记录从s到s最短路径条数,显然为1啦
for(int i=0;i<n;i++){
//循环n次
int u=-1,MIN=inf;//u使d[u]最小,MIN存放该最小的d[u],u和min是用来记录d[u]的
for(int j=0;j<n;j++){
if(vis[j]== false&&d[j]<MIN){
//找到未访问的顶点中d[]最小的
u=j;
MIN=d[u];
}
}
//找不到小于inf的d[u],说明剩下的顶点和起点s不相通
if(u==-1) return;
vis[u]=true;//标记u已访问
for(int v=0;v<n;v++){
//如果v未访问,且u能到达v,且以u为中介点可以使d[v]更优
if(vis[v]==false&&G[u][v]!=inf){
if(d[u]+G[u][v]<d[v]){
d[v]=d[u]+G[u][v];//覆盖d[v]
w[v]=w[u]+weight[v];//覆盖w[v],加上一个v处的weight值
num[v]=num[u];//这个时候最短路径条数就相等啦,num[v]=num[u]
}else if(d[u]+G[u][v]==d[v]){
//找到一条相同长度的路径
if(w[u]+weight[v]>w[v]){
//以u为中介点时候点权更大
w[v]=w[u]+weight[v];//w[v]继承w[u]
}//注意最短路径条数与点权无关,写在外面
num[v]=num[v]+num[u];//到达v的最短路径条数又得加上到达u的最短路径条数,因为从u过来也能到达v了,有两种走法
}
}
}
}
}
int main(){
scanf("%d%d%d%d",&n,&m,&st,&ed);
for(int i=0;i<n;i++){
scanf("%d",&weight[i]);//读入点权
}
int u,v;
fill(G[0],G[0]+maxv*maxv,inf);//初始化图G,因为对于二维数组而言,G[0]才是G[0][0]的首地址
for(int i=0;i<m;i++){
scanf("%d%d",&u,&v);
scanf("%d",&G[u][v]);//读入边权
G[v][u]=G[u][v];//从u到u等于从v到u毕竟是无向图
}
Dijkstra(st);//DJ上场,从起点进入
printf("%d %d\n",num[ed],w[ed]);//从终点输出,最短距离条数,最短路径中的最大点权
return 0;
}