Description
农夫John发现做出全威斯康辛州最甜的黄油的方法:糖。把糖放在一片牧场上,他知道N(1<=N<=500)只奶牛会过来舔它,这样就能做出能卖好价钱的超甜黄油。当然,他将付出额外的费用在奶牛上。
农夫John很狡猾。像以前的Pavlov,他知道他可以训练这些奶牛,让它们在听到铃声时去一个特定的牧场。他打算将糖放在那里然后下午发出铃声,以至他可以在晚上挤奶。
农夫John知道每只奶牛都在各自喜欢的牧场(一个牧场不一定只有一头牛)。给出各头牛在的牧场和牧场间的路线,找出使所有牛到达的路程和最短的牧场(他将把糖放在那)
Input
第一行: 三个数:奶牛数N,牧场数(2<=P<=800),牧场间道路数C(1<=C<=1450)
第二行到第N+1行: 1到N头奶牛所在的牧场号
第N+2行到第N+C+1行: 每行有三个数:相连的牧场A、B,两牧场间距离D(1<=D<=255),当然,连接是双向的
Output
一行 输出奶牛必须行走的最小的距离和
Sample Input
3 4 5
2
3
4
1 2 1
1 3 5
2 3 7
2 4 3
3 4 5
Sample Output
8
{说明:放在4号牧场最优 }
SPFA算法
BFS
(tu有点丑,不要介意)
1
1
1为起点,首先会扩展到
2
、
3
2、3
2、3
d
i
s
[
1
]
=
0
,
d
i
s
[
2
]
=
1
,
d
i
s
[
3
]
=
9
,
d
i
s
[
4
dis[1]=0,dis[2]=1,dis[3]=9,dis[4
dis[1]=0,dis[2]=1,dis[3]=9,dis[4~
7
]
=
∞
7]=∞
7]=∞
以
2
2
2为起点,扩展
4
、
5
4、5
4、5
d
i
s
[
4
]
=
7
,
d
i
s
[
5
]
=
2
,
d
i
s
[
6
dis[4]=7,dis[5]=2,dis[6
dis[4]=7,dis[5]=2,dis[6~
7
]
=
∞
7]=∞
7]=∞
以
3
3
3为起点,扩展不了4,因为4已经在队列里了
以
4
4
4为起点,扩展
7
7
7,但是
7
7
7现在不是最佳答案
d
i
s
[
4
]
=
7
,
d
i
s
[
5
]
=
2
,
d
i
s
[
6
]
=
∞
,
d
i
s
[
7
]
=
10
dis[4]=7,dis[5]=2,dis[6]=∞,dis[7]=10
dis[4]=7,dis[5]=2,dis[6]=∞,dis[7]=10
以
5
5
5为起点,扩展
6
6
6
d
i
s
[
4
]
=
7
,
d
i
s
[
5
]
=
2
,
d
i
s
[
6
]
=
3
,
d
i
s
[
7
]
=
10
dis[4]=7,dis[5]=2,dis[6]=3,dis[7]=10
dis[4]=7,dis[5]=2,dis[6]=3,dis[7]=10
以
7
7
7为起点不能进行扩展
以
6
6
6为起点,扩展
4
4
4。
4
4
4虽然进过队列,但是
4
4
4已经出队了
d
i
s
[
4
]
=
4
,
d
i
s
[
5
]
=
2
,
d
i
s
[
6
]
=
3
,
d
i
s
[
7
]
=
10
dis[4]=4,dis[5]=2,dis[6]=3,dis[7]=10
dis[4]=4,dis[5]=2,dis[6]=3,dis[7]=10
以
4
4
4为起点,扩展
7
7
7。
7
7
7虽然进过队列,但是
7
7
7已经出队了
以
7
7
7为起点不能进行扩展
d
i
s
[
7
]
=
7
dis[7]=7
dis[7]=7
解题思路
SPFA是单源最短路,那么需要枚举起点。求出最短路后,把奶牛到糖的路径全部统计出来,再求min。
邻接表
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=0x7fffffff;
struct DT{
int to,l,next;
}a[30000];
int dis[10000],head[10000],pd[6000],n,m,k,Gun=maxn,num;
int h,t,v[10000],f[10000];
void SPFA(int s){
memset(f,0,sizeof(f));
h=0,t=1,v[1]=s,dis[s]=0,f[s]=1;
while(h++<t){
for(int i=head[v[h]];i;i=a[i].next){
if(dis[v[h]]+a[i].l<dis[a[i].to]){//如果可以松弛
dis[a[i].to]=dis[v[h]]+a[i].l;
if(!f[a[i].to]){//入队
v[++t]=a[i].to;
f[a[i].to]=1;
}
}
}
f[v[h]]=0;
//出队的点要重新赋为0,不然例子中的4和7,就不能再进来了
}
}
int main(){
scanf("%d%d%d",&m,&n,&k);
for(int i=1;i<=m;i++)
scanf("%d",&pd[i]);
for(int i=1;i<=k;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
a[++num].to=y,a[num].l=z,a[num].next=head[x],head[x]=num;
a[++num].to=x,a[num].l=z,a[num].next=head[y],head[y]=num;//邻接表
}
for(int g=1;g<=n;g++){
memset(dis,0x7f,sizeof(dis));
SPFA(g);
int b=0;
for(int i=1;i<=m;i++)
b+=dis[pd[i]];//把奶牛的路径加起来
Gun=min(Gun,b);//取min
}
printf("%d",Gun);
}
STL
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int maxn=0x7fffffff;
struct DT{
int to,l,next;
}a[30000];
int dis[10000],head[10000],pd[6000],n,m,k,Gun=maxn,num;
queue<int> v;
int h,t,f[10000];
void SPFA(int s){
memset(f,0,sizeof(f));
v.push(s);
h=0,t=1,dis[s]=0,f[s]=1;
while(!v.empty()){
for(int i=head[v.front()];i;i=a[i].next){
if(dis[v.front()]+a[i].l<dis[a[i].to]){
dis[a[i].to]=dis[v.front()]+a[i].l;
if(!f[a[i].to]){
v.push(a[i].to);
f[a[i].to]=1;
}
}
}
f[v.front()]=0;
v.pop();
}
}
int main(){
scanf("%d%d%d",&m,&n,&k);
for(int i=1;i<=m;i++)
scanf("%d",&pd[i]);
for(int i=1;i<=k;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
a[++num].to=y,a[num].l=z,a[num].next=head[x],head[x]=num;
a[++num].to=x,a[num].l=z,a[num].next=head[y],head[y]=num;
}
for(int g=1;g<=n;g++){
memset(dis,0x7f,sizeof(dis));
SPFA(g);
int b=0;
for(int i=1;i<=m;i++)
b+=dis[pd[i]];
Gun=min(Gun,b);
}
printf("%d",Gun);
}