系兄弟就来砍我
时间限制: 1 Sec 内存限制: 128 MB
题目描述
渣渣灰因为一句“大家好,我系渣渣辉,系兄弟就来砍我”引得众粉丝纷纷拿两米长的大刀寻找。
现有n个据点,编号(1~n),有m条单向路使据点相连。每个据点仅有一个人。
这n个人中有k个粉丝。其中渣渣灰在s据点处。请问这k个粉丝到渣渣灰的最短距离是多少
输入
首行输入nmks。(k<=n<=100m<=500)s为渣渣灰所在位置
接下来m行,每行输入x,y,z,表示从x到y的距离是z,由于是单向边,则y到x的距离不一定是z。
接下来k个数字,表示粉丝所在据点。
输出
对于每一个粉丝,输出对应的最短距离。
样例输入
3 3 2 1
1 2 1
2 3 1
3 1 1
2 3
样例输出
2 1
提示
数据保证k个粉丝均能到达渣渣灰的据点
分析:
Dijkstra算法求单源最短路裸题,因为要求k个粉丝(起点)到 S 终点的最短距离,如果正向建边,求k次最短路会超时
所以考虑逆向建边,求S点到所有点的最短距离,储存在dis数组中
既然要求k个点到s点的最短路,我们可以反过来求s到这k个点的最短路。这样就变成了单源最短路问题,dijkstra算法和spfa算法都可以做。由于图为有向图,我们在存图时反向存图即可,原本a[i][j]表示i->j,我们可以将它重新定义为j->i,或者存图时直接写成a[j][i]即可。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 107;
const int inf = 0x3f3f3f3f; //需将road及dis初始化为正无穷inf
int n,m,k,s;
int dis[maxn]; //储存各个点到源点的最短距离,dis[s]为0
int road[maxn][maxn]; //两点之间直接距离关系
bool vis[maxn]; //判断源点到该点的距离是否为最短距离
int fans[maxn]; //粉丝
void dijkstra(int s)
{
memset(vis, false, sizeof(vis));//标记是否求出最短路径
vis[s] = true;//标记起点到这一点的最小距离已经求出
for(int i = 1; i <= n; i++)
dis[i] = road[s][i];//初始化起点到每一个点的距离
for(int u = 1; u<n; u++)
{
int minD = inf,k = -1;
for(int i = 1; i<= n; i++)
{
if(!vis[i]&&dis[i]<minD)
{
k = i;//记录下标
minD = dis[i];//记录最小值
}
}
vis[k] = true;//标记已经访问过
//松弛操作
for(int i = 1; i<= n; i++)
{
if(!vis[i]&&dis[k]+road[k][i]<dis[i])
{
dis[i]=dis[k]+road[k][i];
}//if
}//for
}
}
int main()
{
while(scanf("%d%d%d%d",&n,&m,&k,&s)!=EOF){
memset(road,inf,sizeof(road));
for(int i=1;i<=m;i++)
{
int a,b,d;
scanf("%d%d%d",&a,&b,&d);
road[b][a]=min(d,road[b][a]);//逆向建边
//起点是fans[i],终点是S
}
for(int i=1;i<=k;i++)
scanf("%d",&fans[i]);
dis[s]=0;
dijkstra(s);
for(int i=1;i<=k;i++)
{
printf("%d",dis[fans[i]]);
if(i==k) printf("\n");
else printf(" ");
}
}
return 0;
}