题目大意
题目链接
p
p
p个牧场之间有
c
c
c条路,有
n
n
n只在不同牧场的奶牛(可能有多头奶牛在同一个牧场)要到一个牧场去,找到一个牧场使所有奶牛需要走的距离最短。
输入格式
第一行为三个整数
n
、
p
、
c
n、p、c
n、p、c。
第
2
2
2~
n
+
1
n+1
n+1行为奶牛所在的牧场。
第
n
+
2
n+2
n+2~
n
+
c
+
1
n+c+1
n+c+1行,每行3个整数
a
、
b
、
d
a、b、d
a、b、d,表示
a
a
a牧场到
b
b
b牧场之间有一条长度为
d
d
d的双向道路。
解题思路
如图
B
、
C
、
D
B、C、D
B、C、D牧场各有一头奶牛,最优的方案是选择
D
D
D牧场。
不难看出,这是一个最短路问题,枚举一个牧场,再将每个牧场的奶牛数
∗
*
∗离枚举的这个牧场的最短路,最后找出与各个牧场距离最短的牧场,就是得到的最终答案。
这题的
n
n
n范围最大达到了
500
500
500,正常情况下都不会想到Floyed做法,因为
O
(
n
3
)
O(n^3)
O(n3)的做法一定会T,但由于道路是双向的,因此从
a
a
a牧场去到
b
b
b牧场的距离与从
b
b
b牧场去到
a
a
a牧场的距离是一样的,因此在第三层循环时
j
j
j只需要循环到
i
i
i,更新
d
i
s
i
,
j
dis_{i,j}
disi,j时将
d
i
s
j
,
i
dis_{j,i}
disj,i同时更新即可。
代码
#include<bits/stdc++.h>
using namespace std;
int n,m,c,dis[1005][1005],mc[1005];
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
memset(dis,0x3f,sizeof(dis));
for(int j=1;j<=n;j++)
dis[j][j]=0;
cin>>n>>m>>c;
for(int i=1;i<=n;i++)
{
int x;
cin>>x;
mc[x]++;
}
for(int i=1;i<=c;i++)
{
int x,y,w;
cin>>x>>y>>w;
dis[x][y]=dis[y][x]=w;
}
for(int k=1;k<=m;k++)
for(int i=1;i<=m;i++)
for(int j=1;j<i;j++)
{
if(i!=j&&j!=k&&i!=k&&dis[i][j]>dis[i][k]+dis[k][j])
{
dis[i][j]=dis[i][k]+dis[k][j];
dis[j][i]=dis[i][j];
}
}
int ans=1e10;
for(int i=1;i<=m;i++)
{
int sum=0;
for(int j=1;j<=m;j++){
if(i!=j) sum+=mc[j]*dis[i][j];
}
ans=min(ans,sum);
}
cout<<ans;
return 0;
}