城市平乱
时间限制:
1000 ms | 内存限制:
65535 KB
难度:
4
-
描述
-
南将军统领着N个部队,这N个部队分别驻扎在N个不同的城市。
他在用这N个部队维护着M个城市的治安,这M个城市分别编号从1到M。
现在,小工军师告诉南将军,第K号城市发生了暴乱,南将军从各个部队都派遣了一个分队沿最近路去往暴乱城市平乱。
现在已知在任意两个城市之间的路行军所需的时间,你作为南将军麾下最厉害的程序员,请你编写一个程序来告诉南将军第一个分队到达叛乱城市所需的时间。
注意,两个城市之间可能不只一条路。
-
输入
-
第一行输入一个整数T,表示测试数据的组数。(T<20)
每组测试数据的第一行是四个整数N,M,P,Q(1<=N<=100,N<=M<=1000,M-1<=P<=100000)其中N表示部队数,M表示城市数,P表示城市之间的路的条数,Q表示发生暴乱的城市编号。
随后的一行是N个整数,表示部队所在城市的编号。
再之后的P行,每行有三个正整数,a,b,t(1<=a,b<=M,1<=t<=100),表示a,b之间的路如果行军需要用时为t
数据保证暴乱的城市是可达的。
输出
- 对于每组测试数据,输出第一支部队到达叛乱城市时的时间。每组输出占一行 样例输入
-
1 3 8 9 8 1 2 3 1 2 1 2 3 2 1 4 2 2 5 3 3 6 2 4 7 1 5 7 3 5 8 2 6 8 2
样例输出
-
4
#include<iostream>//导入输入输出流头文件
#include<string.h>//需要用到memset
using namespace std;//导入命名空间
#define MAXN 1010//定义最大顶点树
#define MAXNUM 0x3f3f3f3f//定义无穷大
int gragh[MAXN][MAXN];//定义图
int d[MAXN];//定义最小距离
bool v[MAXN];//定义是否确定顶点到改点的最小路径值
int n,m,p,q;
int flag[MAXN];//驻扎标记
void djst(int s)//迪杰斯特拉求最小路径
{//求定点s到所有点的最小路径,保存在数组d中
for(int i=1;i<=m;i++)
{
d[i]=gragh[s][i];//初始化d为s到所有点的直接距离,包括无穷大
}
v[s]=true;//把顶点加入到已经确定的点中
d[s]=0;//到自己的代价是0
if(flag[s]==1)//如果驻扎的地方就是暴乱的地方,那么我们输出并返回
{
cout<<d[s]<<endl;
return;
}
for(int i=0;i<m-1;i++)//接下来的n-1个点,每次确定定点到一个点的最短路径,并用这个点松弛其他点
{
int tmin=MAXNUM;//定义最小值
int ti=0;//定义最小d的下标
for(int j=1;j<=m;j++)
{
if(!v[j]&&d[j]<tmin)//如果该点还没有确定并且小于tmin
{
tmin=d[j];
ti=j;
}
}
v[ti]=true;//找到后加入已经确定的点
if(flag[ti]==1)//如果该点有部队驻扎输出并返回
{
cout<<d[ti]<<endl;
return;
}
for(int j=1;j<=m;j++)//扫描m个点
{
if(!v[j]&&d[j]>d[ti]+gragh[ti][j])//如果该点没有确定并且本次已经确定的点与某点的距离+本次确定的点与定点的距离比定点到某点的距离还小
{
d[j]=d[ti]+gragh[ti][j];//更新d
}
}
}
}
void init()
{
for(int i=0;i<=m;i++)
v[i]=false;//初始化标志数组全部是false
memset(gragh,0x3f,sizeof(gragh));//图全部是最大值就是说谁和谁都不连通
memset(flag,0,sizeof(flag));//初始化刚开始没有点有军队驻扎
}
int main()
{
int ncase;
cin>>ncase;//输入测试个数
while(ncase--)
{
cin>>n>>m>>p>>q;
init();//初始化
for(int i=0;i<n;i++)
{
int num;
cin>>num;
flag[num]=1;//驻扎标志
}
for(int i=0;i<p;i++)
{
int v,u,d;
cin>>v>>u>>d;
gragh[v][u]=d;
gragh[u][v]=d;//建图
}
djst(q);//由于迪杰斯特拉有个特性就是最先确定出的最短路径的点与定点的距离就越近,那么如果算法中一旦确定的点,并且有部队驻,那么该点所在的部队就是最快到达的
}
}
题目分析:终点只有一个也就是这个可以算是单源求最小路径,并且顶点的数目最大是1000,并且没有负权,那么我就果断选择迪杰斯特拉算法
但是要求起点是驻扎军队的城市,所以我们需要开个数组标记为1
我们只需要把驻扎军队的城市距离定点的最短路径保存到一个数组中并用sort排序取第一个就好了
但是这样无非有在sort上耗时,并且为保存驻扎军队城市到定点最短路径的数组加大控件开销
所以我们可以利用迪杰斯特拉的一个特性优化时间复杂度
众所周知,迪杰斯特拉有个特性就是最早确定的点到源点的最小路径就越小,因此每当确定一个点到源点的最小路径,就看看是不是驻扎军队的点,如果是就直接输出,输出的点的一定是所有距离源点的驻扎军队的点的最小距离中最小的,因为他是驻扎军队中最先确立的这是优化前后对比
优化前:
优化后: