P1828 香甜的黄油 Sweet Butter

原题链接

P1828 香甜的黄油 Sweet Butter

题目大意

n ( 1 ≤ n ≤ 500 ) n(1\le n\le 500) n(1n500) 头牛,每头牛都在自己的牧场内。有 1 ≤ c ≤ 1450 1\le c\le 1450 1c1450 对牧场之间有一条路,且每条路的路程不同。现在,让所有牛去到其中一个牧场,求所有牛走过的路程总和的最小值。

解题思路

很明显,这一题需要使用最短路算法。因为路是双向的,所以我们可以计算从枚举一个牧场,再计算从这个牧场到其他牧场的最短路,将其总和加起来,求最小值。

代码实现(Dijkstra队列优化, O ( n ∗ l o g 2 n ) O(n*log_2n) O(nlog2n)

#include<iostream>
#include<fstream>
#include<set>
#include<map>
#include<ctime>
#include<cstring>
#include<string>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
using namespace std;
struct node{
	double x,y;
} xy[110];
struct node2{
	double _dis;
	int x;
};
int n,m,c,b[1010];
double Min[1010],d,ans=0x7fffffff;
vector<node2> a[1010];
priority_queue<node2> q;//优先队列
int f,t;
bool operator<(node2 q,node2 h)//重载运算符,如果使用pair可以不用
{
	if(q._dis!=h._dis)//第一关键字
		return q._dis<h._dis;
	return q.x<h.x;//第二关键字
}
bool operator>(node2 q,node2 h)//重载运算符,如果使用pair可以不用
{
	if(q._dis!=h._dis)//第一关键字
		return q._dis>h._dis;
	return q.x>h.x;//第二关键字
}
void work(int f)//Dijkstra算法
{
	memset(Min,0x7f,sizeof(Min));
	q.push((node2){0,f});
	Min[f]=0;
	while(!q.empty()){
		int now_x=q.top().x;
		double now_dis=-q.top()._dis;//逆用大根堆
		q.pop();
		if(Min[now_x]<now_dis) continue;
		for(int i=0;i<a[now_x].size();i++){
			int next=a[now_x][i].x;
			if(Min[next]>now_dis+a[now_x][i]._dis){
				Min[next]=now_dis+a[now_x][i]._dis;
				q.push((node2){-Min[next],next});
			}
		}
	}
}
int main()
{
	cin>>n>>c>>m;
	for(int i=1;i<=n;i++)
		cin>>b[i];
	for(int i=1;i<=m;i++){
		cin>>f>>t>>d;
		a[f].push_back((node2){d,t});//建边
		a[t].push_back((node2){d,f});//建边
	}
	for(int i=1;i<=c;i++){//枚举终点牧场
		work(i);//进行最短路计算
		double ans2=0;
		for(int j=1;j<=n;j++)//最短路长度累加
			ans2+=Min[b[j]];
		ans=min(ans2,ans);
	}
	cout<<ans;
	return 0;
} 

样例

输入

3 4 5
2
3
4
1 2 1
1 3 5
2 3 7
2 4 3
3 4 5

输出

8
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值