【问题描述】
农夫John发现了做出全威斯康辛州最甜的黄油的方法:把糖放在一片牧场上,他知道他所有的N只奶牛会过来舔它,这样就能做出能卖好价钱的超甜黄油。
农夫John很狡猾。就像以前的巴甫洛夫,他知道他可以训练这些奶牛,让它们在听到铃声时去一个特定的牧场。他打算将糖放在那里然后下午发出铃声,好让他可以在晚上挤奶。
农夫John知道开始时,每只奶牛都在各自喜欢的牧场(一个牧场不一定只有一头牛)。给出各头牛所在的牧场和牧场间的路线,找出使所有牛到达的路程之和最短的牧场(他将把糖放在那)。
【输入格式】
第 1 行: 三个数:奶牛数 N,牧场数 P,牧场间道路数 C。
第 2 行到第 N+1 行: 1 到 N 头奶牛所在的牧场号。
第 N+2 行到第 N+C+1 行: 每行有三个数:相连的牧场A、B,两牧场间距 D,当然,连接是双向的。
【输出格式】
一行 输出奶牛必须行走的最小的距离和。
【输入样例】
3 4 5
2
3
4
1 2 1
1 3 5
2 3 7
2 4 3
3 4 5
【输出样例】
8
【数据范围】
2 <= P <= 800
1 <= C <= 1450
1 <= D <= 255
1 <= N <=500
【思路梳理】
数据规模不大,再加上没有什么其他的好办法,所以可以依次穷举所有的牧场,假设将糖放在第i个牧场,求出第i个牧场到其他所有牧场的最小距离之和。对于枚举的所有最优结果,直接取一个最小值输出即可。
给出一个伪代码方便读者理解:
void solve()
{
依次穷举每一个牧场:
将dist(距离)置为无穷大,
以该牧场为出发源使用SPFA算法/Dijstra算法求出所有点到该出发源的距离dist[i]。
将所有的距离相加,与目前最优结果进行比较。
输出最优解
}
【Cpp代码】
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#define maxnum 505
#define maxn 805
#define inf 2000000005
using namespace std;
int num,p,c,dist[maxn],loca[maxnum],cnt=inf;
vector<int>g[maxn],w[maxn];
bool inq[maxn];
int SPFA(int s)//改造了一下SPFA算法,让他返回距离之和,一个漏洞是可能存在有些点不能够到达使得最小距离的加和超过了int上界
{
int ans=0;
memset(inq,false,sizeof(inq));
for(int i=1;i<=p;i++) dist[i]=inf;
queue<int>q;
q.push(s);
inq[s]=true;
dist[s]=0;
while(!q.empty())
{
int i=q.front();q.pop();
inq[i]=false;
for(int j=0;j<g[i].size();j++)
{
int k=g[i][j],c=w[i][j];
if(dist[k]>dist[i]+c)
{
dist[k]=dist[i]+c;
if(!inq[k])
{
inq[k]=true;
q.push(k);
}
}
}
}
for(int i=1;i<=num;i++)
ans+=dist[loca[i]];
return ans;
}
int main()
{
//freopen("in.txt","r",stdin);
cin>>num>>p>>c;
for(int i=1;i<=num;i++)//记录有奶牛的牧场的编号
scanf("%d",&loca[i]);
for(int i=1;i<=c;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
g[x].push_back(y);w[x].push_back(z);
g[y].push_back(x);w[y].push_back(z);//建立存储结构
}
for(int i=1;i<=p;i++)//对于每一个牧场依次枚举,使用SPFA算法求出各点的最短距离之和
cnt=min(cnt,SPFA(i));
cout<<cnt;
return 0;
}