PTA1003 - Emergency - Dijkstra的变形
题意
第一行给出四个数,分别代表城市数量(0 ~ n-1)、道路数量m、起点s、终点t。
第二行给出n个数,代表第i个城市救援队的数量
接下去给出m行,每行给出三个数x、y、z,表示x->y 距离z,是双向路。
最后让我们输出s->t的最短路条数 和 能聚集到的救援队的最大数量。
思路
本题是一个Dijkstra的变形,变形的部分就是下面的关键部分代码。
我们开两个数组保存结果,分别是ans1和ans2,
ans1:起点s到每个点最短路的数量 ans2:起点s到每个点(在距离最短的情况下)最多救援几支队伍。
但是要非常非常非常注意的一点就是:book数组标记的时候,book[s]=0而不是等于1,因为如果题目给出来的起点s和终点t恰好是同一个点,那么也是存在一条路线的。这个会造成样例答案都不对。
关键部分代码:
if(!book[j])
{
if(dis[k]+e[k][j]<dis[j]) // 找到一条更短的路
{
dis[j]=dis[k]+e[k][j];
ans1[j]=ans1[k]; // 更新ans1:起点s到每个点最短路的数量
ans2[j]=ans2[k]+num[j];
}
else if(dis[k]+e[k][j]==dis[j]) // 如果最短路路径相等
{
ans1[j]=ans1[j]+ans1[k];
if(ans2[k]+num[j]>ans2[j])
ans2[j]=ans2[k]+num[j];
}
}
AC代码
#include<iostream>
#include<string>
#include<algorithm>
#include<stdio.h>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
//5 6 0 2 城市数量0~n-1 路数量m s t
//1 2 1 5 3 n个数 第i个城市救援队的数量
//m行 x->y 距离z 双向路
//0 1 1
//0 2 2
//0 3 1
//1 2 1
//2 4 1
//3 4 1
//output:
//s->t的最短路条数 能聚集到的救援队的最大数量
const int N=550;
int e[N][N],dis[N],num[N],n,m,s,t,ans1[N],ans2[N];
//ans1:起点s到每个点最短路的数量 ans2:起点s到每个点(在距离最短的情况下)最多救援几支队伍
bool book[N];
void dijkstra()
{
ans1[s]=1,ans2[s]=num[s]; // 最短路肯定有起码有一条,救援队数量起码有本身的数量(理解有问题)
for(int i=0;i<n;i++)
dis[i]=e[s][i]; // dis[i]=inf;
//book[s]=1; 重要易错点 起点不能标记,因为起点自身到自身也是一条路径
dis[s]=0;
for(int i=0;i<n;i++)
{
int mi=inf,k;
for(int j=0;j<n;j++)
{
if(!book[j]&&dis[j]<mi)
k=j,mi=dis[j];//book[j]=1;
}
book[k]=1;
for(int j=0;j<n;j++)
{
if(!book[j])
{
if(dis[k]+e[k][j]<dis[j]) // 找到一条更短的路
{
dis[j]=dis[k]+e[k][j];
ans1[j]=ans1[k]; // 更新ans1:起点s到每个点最短路的数量
ans2[j]=ans2[k]+num[j];
}
else if(dis[k]+e[k][j]==dis[j]) // 如果最短路路径相等
{
ans1[j]=ans1[j]+ans1[k];
if(ans2[k]+num[j]>ans2[j])
ans2[j]=ans2[k]+num[j];
}
}
}
}
}
int main()
{
cin>>n>>m>>s>>t;
for(int i=0;i<n;i++)
cin>>num[i];
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(i==j)
e[i][j]=0;
else
e[i][j]=inf;
}
}
for(int i=0;i<m;i++)
{
int x,y,z;
cin>>x>>y>>z;
if(z<e[x][y]||z<e[y][x])
e[x][y]=e[y][x]=z;
}
dijkstra();
cout<<ans1[t]<<" "<<ans2[t];
return 0;
};