Sweet Butter 香甜的黄油
Greg Galperin -- 2001
农夫John发现做出全威斯康辛州最甜的黄油的方法:糖。把糖放在一片牧场上,他知道N(1<=N<=500)只奶牛会过来舔它,这样就能做出能卖好价钱的超甜黄油。当然,他将付出额外的费用在奶牛上。描述
农夫John很狡猾。他知道他可以训练这些奶牛,让它们在听到铃声时去一个特定的牧场。他打算将糖放在那里然后下午发出铃声,以至他可以在晚上挤奶。
农夫John知道每只奶牛都在各自喜欢的牧场呆着(一个牧场不一定只有一头牛)。给出各头牛在的牧场和牧场间的路线,找出使所有牛到达的路程和最短的牧场(他将把糖放在那)。
格式
PROGRAM NAME: butter
INPUT FORMAT:
(file butter.in)
第一行: 三个数:奶牛数N,牧场数P(2<=P<=800),牧场间道路数C(1<=C<=1450).
第二行到第N+1行: 1到N头奶牛所在的牧场号.
第N+2行到第N+C+1行: 每行有三个数:相连的牧场A、B,两牧场间距(1<=D<=255),当然,连接是双向的.
OUTPUT FORMAT:
(file butter.out)
一行 输出奶牛必须行走的最小的距离和.
SAMPLE INPUT
3 4 5
2
3
4
1 2 1
1 3 5
2 3 7
2 4 3
3 4 5
样例图形
P2
P1 @--1--@ C1
\ |\
\ | \
5 7 3
\ | \
\| \ C3
C2 @--5--@
P3 P4
SAMPLE OUTPUT
8
{说明: 放在4号牧场最优. }
分析:此题的实际模型如下:给定一个有P个顶点的无向图,选择一个顶点,使得从该点到给定的N个顶点的权值之和最小。
堆优化Dijkstra算法
求每对顶点之间的最短路径首先想到的便是Floyd算法:但P的范围是(P<=800)则时间复杂度为O(800^3),显然会超时。此时可以考虑使用Dijkstra算法求最短路径(Dijkstra是O(N^2)的算法),但直接使用Dijkstra仍然会超时O(800*800^2)=O(800^3),此时可以用堆进行优化。
Dijkstra算法每次都需要在Dist[]数组中寻求一个最小值,如果图很大,则在此处花费的时间会很多,而堆则可以在O(1)的时间内马上求得最小值,并且维护一个堆所需的时间都是在log级的。因此考虑把Dist[]数组的值用堆来存储。而且用STL中的priority_queue优化dijkstra也十分方便!(某神牛语录:“Dijkstra用堆优化比不用堆优化都好写”。。。)
SPFA算法
对于枚举的每个牧场i,用SPFA求出到每个点的最短路如下:dist[j]表示i->j的距离,初始值为maxint,其中dist[i]=0。维护一个队列,初始为q[1]=i;由队首枚举其他的牧场j更新牧场i到j的最短距离并同时拓展队列。直到队列空为止。这样就求出了点i到所有点的最短距离。
图储存方法:有人说用邻接表,但是我认为用链式前向星(参见Malash神牛blog)(详见http://malash.me/200910/linked-forward-star/ )更方便而且省空间。可以在不增加时间复杂度的前提下把空间优化到1000k左右。
SPFA邻接表代码:
/*
ID:138_3531
LANG:C++
TASK:butter
*/
#include<iostream>
#include<cstring>
#include<string>
#include<fstream>
#include<queue>
#include<climits>
#include<vector>
using namespace std;
int num[1000];
int dist[1000];
typedef struct Edge
{
int v;
int map;
}Edge;
vector <Edge> edge[1000];
void spfa(int s)
{
bool vis[1000];
memset(dist,127,sizeof(dist));
memset(vis,0,sizeof(vis));
dist[s]=0;
queue <int> Q;
Q.push(s);
vis[s]=1;
while(!Q.empty())
{
int k=Q.front();
Q.pop();
vis[k]=0;
for (int i=0;i<edge[k].size();i++)
{
int to=edge[k][i].v;
int mapp=edge[k][i].map;
if (dist[to]>dist[k]+mapp)
{
dist[to]=dist[k]+mapp;
if (!vis[to])
{
Q.push(to);
vis[to]=1;
}
}
}
}
}
int main(){
ifstream fin("butter.in");
ofstream fout("butter.out");
int n,p,c;
fin>>n>>p>>c;
memset(num,0,sizeof(num));
for (int i=1;i<=n;i++)
{
int t;
fin>>t;
num[t]++;
}
for (int i=0;i<c;i++)
{
int a,b;
fin>>a>>b;
int mapd;
fin>>mapd;
Edge temp;
temp.v=b;
temp.map=mapd;
edge[a].push_back(temp);
temp.v=a;
edge[b].push_back(temp);
}
long long ans[1000];
memset(ans,0,sizeof(ans));
long long minans=INT_MAX;
for (int i=1;i<=p;i++)
{
spfa(i);
for (int j=1;j<=p;j++)
ans[i]+=num[j]*dist[j];
if (ans[i]<minans)
minans=ans[i];
}
fout<<minans<<endl;
return 0;
}