1345:【例4-6】香甜的黄油

【解题思路】
       将题目叙述转为图论概念,牧场为顶点,牧场间的路线为边。该题一个顶点上有多头牛,这个后面再考虑。记有V个顶点,E条边,有n头牛,每头牛所在顶点为v 1 , v 2 , . . . v n ,d(i,j)为顶点i,j间的最短路径长度。题目要问的问题是,选择一个顶点c,使得

最小。
        如果已知每头牛所在顶点到其它任意顶点的最短路径长度,那么接下来就可以遍历所有顶点,记遍历到的顶点为i,选择顶点i为放糖的地方,求所有牛所在顶点到顶点i的最短路径加和,这一步的复杂度为O(V⋅n)。问题落在如何求每头牛所在顶点到其它任意顶点的最短路径。
       使用Floyd算法,求所有顶点间的最短路径长度。题目给定顶点数(牧场数)最大为800,Floyd算法的复杂度为O(V^3),800^3=5.12*10^8,复杂度达到10^8数量级很可能会超时,所以不能用Floyd算法。
       如果用单源最短路径算法,需要对每头牛所在顶点跑一次单源最短路径算法。算法整体复杂度为:O(n)乘以所用的单源最短路径算法的复杂度。

  • 考虑使用朴素Dijkstra算法,整体复杂度为O(n⋅V^2),计算 500*800^2=3.2*10^8,不可行。
  • 使用SPFA算法,复杂度为O(kE),k为每个顶点平均入队次数,在稀疏图中一般小于2,可以认为等于2。用SPFA算法做该问题,整体复杂度为O(n⋅kE),计算 500*2*1500 = 1.5*10^6,可行。

以上是思考过程,该题做法为:
       遍历每个顶点v,求每个牛所在顶点到v的最短路径长度乘以那里牛的数量,再加和。求这些加和中的最小值。

【参考代码】

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=805;
int n,p,c;//奶牛数n 牧场数p 牧场间道路数c
int b[N],num[N],w[N][N];
int a[N][N],dis[N],qu[10000];
bool v[N];
int x,y,t,minnl;
int main()
{
	cin>>n>>p>>c;
	for(int i=1;i<=p;i++)
		for(int j=1;j<=p;j++) w[i][j]=0x7f7f7f7f;
	for(int i=1;i<=n;i++)cin>>b[i];//第i头奶牛所在的牧场
	for(int i=1;i<=c;i++){
		cin>>x>>y>>t;
		w[x][y]=w[y][x]=t;//邻接矩阵
		a[x][++num[x]]=y;//num[i]i牧场邻接牧场的个数
		a[y][++num[y]]=x;//a[y][1~num[y]]储存所有与y牧场邻接的牧场号
	}
	minnl=0x7f7f7f7f;
	for(int i=1;i<=p;i++){//p个牧场
		for(int j=1;j<=p;j++) dis[j]=0x7f7f7f7f;
		memset(qu,0,sizeof(qu));//队列初始化
		memset(v,false,sizeof(v));//初始化访问
		dis[i]=0;qu[1]=i;//初始化距离  i牧场入队
		int head=0,tail=1;//队头、队尾
		v[i]=true;//已访问标记
		do{
			head++;
			int u=qu[head];
			v[u]=false;
			for(int j=1;j<=num[u];j++)
				if(dis[a[u][j]]>dis[u]+w[u][a[u][j]]){
					dis[a[u][j]]=dis[u]+w[u][a[u][j]];
					if(!v[a[u][j]]){
						tail++;
						qu[tail]=a[u][j];
						v[a[u][j]]=true;
					}
				}	
		}while(head<tail);
		int temp=0;
		for(int j=1;j<=n;j++) temp+=dis[b[j]];
		if(temp<minnl)minnl=temp;	
	}
	cout<<minnl;
	return 0;
}

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以先创建一个空字典,然后循环遍历每个购物清单,将其转化为键值对的形式,最后将所有的键值对合并到空字典中,具体实现如下: ``` shopping_list = [ ['面包', '黄油', '尿布', '啤酒'], ['咖啡', '糖', '小甜饼', '鲑鱼', '啤酒'], ['面包', '黄油', '咖啡', '尿布', '啤酒', '鸡蛋'], ['面包', '黄油', '鲑鱼', '鸡'], ['鸡蛋', '面包', '黄油'], ['鲑鱼', '尿布', '啤酒'], ['面包', '茶', '糖', '鸡蛋'], ['咖啡', '糖', '鸡', '鸡蛋'], ['面包', '尿布', '啤酒', '盐'], ['茶', '鸡蛋', '小甜饼', '尿布', '啤酒'] ] my_dict = {} for index, item in enumerate(shopping_list): key = f'{index + 1:03d}' # 键值对的标志符按照001,002的格式 value = ', '.join(item) # 将购物清单转化为字符串 my_dict[key] = value print(my_dict) ``` 输出结果为: ``` {'001': '面包, 黄油, 尿布, 啤酒', '002': '咖啡, 糖, 小甜饼, 鲑鱼, 啤酒', '003': '面包, 黄油, 咖啡, 尿布, 啤酒, 鸡蛋', '004': '面包, 黄油, 鲑鱼, 鸡', '005': '鸡蛋, 面包, 黄油', '006': '鲑鱼, 尿布, 啤酒', '007': '面包, 茶, 糖, 鸡蛋', '008': '咖啡, 糖, 鸡, 鸡蛋', '009': '面包, 尿布, 啤酒, 盐', '010': '茶, 鸡蛋, 小甜饼, 尿布, 啤酒'} ``` 其中,`enumerate()`函数用于同时获取购物清单的索引和元素,从而生成键值对的标志符。`join()`方法用于将购物清单转化为字符串,多个物品之间用逗号隔开,方便查看。最后将每个键值对合并到空字典中,得到了最终的结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值