原题链接
题目大意
有 n ( 1 ≤ n ≤ 500 ) n(1\le n\le 500) n(1≤n≤500) 头牛,每头牛都在自己的牧场内。有 1 ≤ c ≤ 1450 1\le c\le 1450 1≤c≤1450 对牧场之间有一条路,且每条路的路程不同。现在,让所有牛去到其中一个牧场,求所有牛走过的路程总和的最小值。
解题思路
很明显,这一题需要使用最短路算法。因为路是双向的,所以我们可以计算从枚举一个牧场,再计算从这个牧场到其他牧场的最短路,将其总和加起来,求最小值。
代码实现(Dijkstra队列优化, O ( n ∗ l o g 2 n ) O(n*log_2n) O(n∗log2n))
#include<iostream>
#include<fstream>
#include<set>
#include<map>
#include<ctime>
#include<cstring>
#include<string>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
using namespace std;
struct node{
double x,y;
} xy[110];
struct node2{
double _dis;
int x;
};
int n,m,c,b[1010];
double Min[1010],d,ans=0x7fffffff;
vector<node2> a[1010];
priority_queue<node2> q;//优先队列
int f,t;
bool operator<(node2 q,node2 h)//重载运算符,如果使用pair可以不用
{
if(q._dis!=h._dis)//第一关键字
return q._dis<h._dis;
return q.x<h.x;//第二关键字
}
bool operator>(node2 q,node2 h)//重载运算符,如果使用pair可以不用
{
if(q._dis!=h._dis)//第一关键字
return q._dis>h._dis;
return q.x>h.x;//第二关键字
}
void work(int f)//Dijkstra算法
{
memset(Min,0x7f,sizeof(Min));
q.push((node2){0,f});
Min[f]=0;
while(!q.empty()){
int now_x=q.top().x;
double now_dis=-q.top()._dis;//逆用大根堆
q.pop();
if(Min[now_x]<now_dis) continue;
for(int i=0;i<a[now_x].size();i++){
int next=a[now_x][i].x;
if(Min[next]>now_dis+a[now_x][i]._dis){
Min[next]=now_dis+a[now_x][i]._dis;
q.push((node2){-Min[next],next});
}
}
}
}
int main()
{
cin>>n>>c>>m;
for(int i=1;i<=n;i++)
cin>>b[i];
for(int i=1;i<=m;i++){
cin>>f>>t>>d;
a[f].push_back((node2){d,t});//建边
a[t].push_back((node2){d,f});//建边
}
for(int i=1;i<=c;i++){//枚举终点牧场
work(i);//进行最短路计算
double ans2=0;
for(int j=1;j<=n;j++)//最短路长度累加
ans2+=Min[b[j]];
ans=min(ans2,ans);
}
cout<<ans;
return 0;
}
样例
输入
3 4 5
2
3
4
1 2 1
1 3 5
2 3 7
2 4 3
3 4 5
输出
8