[http://acm.hdu.edu.cn/showproblem.php?pid=2066]
给定一些起点,一些终点,和一些边的权,构成一个无向图,问所有最短路径和中的最小值。
把 0 作为唯一起点,其他起点到 0 的权为 0 ,用一次 Dijkstra 算法即可算出起点到每个点的最小路径和,最后再取所有终点的最小路径和的最小值即可。
可参考这个比较详细的
[https://www.cnblogs.com/jason2003/p/7222182.html]
给定一个起点,求该起点到其他点的最小路径和
特别注意他不适用于负权边,大概原理就是:
实现大概就是:
const int maxn = (int)1e5+7;
const int INF = (int)2e9+7;
int i,j,k;
int map[maxn][maxn];//假设已经画好了的图
bool vis[maxn];int dis[maxn];//vis标记是否作为过源,dis表示起点到某个点的距离
int ori,minn,ver,sta;//ori储存源的编号,minn用来寻找源的编号,ver是顶点数,sta是起点
void dijkstra(){
for(i=1;i<=ver;i++){
vis[i]=0;
dis[i]=map[sta][i];//假定sta若不与i相连则距离为INF
}//初始化数组
vis[sta]=1;//初始化后sta就已经被当作过源了
for(i=1;i<ver;i++){//还剩至多有ver个源
minn=INF;
for(j=1;j<=ver;j++)
if(!vis[j]&&dis[j]<minn){//如果不是源且起点到该点的距离小于当前最小值
ori=j;
minn=dis[j];
}
vis[ori]=1;//找到了源,标记
if(minn==INF)//离起点最小距离的点是无穷远,算完
break;
for(j=1;j<=ver;j++)
if(!vis[j])//如果不是源就松弛
dis[j]=min(dis[j],dis[ori]+map[ori][j]);
}
}
#include
#include
using namespace std;
const int maxn = 1200;
const int INF = (int)2e9+7;
int i,j,k;
int T,S,D;
int a,b,t;
int sta,tep;
int map[maxn][maxn];
int vis[maxn],dis[maxn];
int ori,minn,ver,ans;
int main(){
while(~scanf("%d%d%d",&T,&S,&D)){
for(i=0;i<maxn;i++){
for(j=0;j<maxn;j++)
map[i][j]=INF;
map[i][i]=0;
vis[i]=0;
dis[i]=INF;
}
ori=ver=0;
//上面是初始化
for(i=0;i<T;i++){
scanf("%d%d%d",&a,&b,&t);
if(t<map[a][b])//这里害死人了,没理解题意ab之间有多条路的意思
map[a][b]=map[b][a]=t;
ver=max(max(ver,a),b);//储存最大顶点
}
for(i=0;i<S;i++){
scanf("%d",&sta);
map[0][sta]=map[sta][0]=0;//起点之间权值为0
}
//上面是录入地图,边界为ver,下面是dijkstra
for(i=0;i<=ver;i++)
dis[i]=map[0][i];
vis[0]=1;
for(i=0;i<ver;i++){
minn=INF;
for(j=0;j<=ver;j++)
if(!vis[j]&&dis[j]<minn){
ori = j;
minn = dis[j];
}
if(minn==INF)
break;
vis[ori] = 1;
for(j=0;j<=ver;j++)
if(!vis[j])
dis[j]=min(dis[j],dis[ori]+map[ori][j]);
}
ans = INF;
for(i=0;i<D;i++){
scanf("%d",&tep);//录入终点
ans=min(ans,dis[tep]);
}
printf("%d\n",ans);
}
}