【图论】【最短路】USACO 3.2 Sweet Butter 香甜的黄油 (Bellman DIJ SPFA)

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 为起点,首先会扩展到 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 ~ 7 ] = 7]=∞
在这里插入图片描述
2 2 为起点,扩展 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 ~ 7 ] = 7]=∞

在这里插入图片描述
3 3 为起点,扩展不了4,因为4已经在队列里了
4 4 为起点,扩展 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

在这里插入图片描述
5 5 为起点,扩展 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
在这里插入图片描述
7 7 为起点不能进行扩展
6 6 为起点,扩展 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
在这里插入图片描述
4 4 为起点,扩展 7 7 7 7 虽然进过队列,但是 7 7 已经出队了
7 7 为起点不能进行扩展
d i s [ 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);
}
发布了45 篇原创文章 · 获赞 0 · 访问量 348

猜你喜欢

转载自blog.csdn.net/qq_39940018/article/details/103745051