野餐规划(最小度限制生成树)

news/2024/11/20 12:25:03/

题目

题目描述

一群小丑演员,以其出色的柔术表演,可以无限量的钻进同一辆汽车中,而闻名世界。

现在他们想要去公园玩耍,但是他们的经费非常紧缺。

他们将乘车前往公园,为了减少花费,他们决定选择一种合理的乘车方式,可以使得他们去往公园需要的所有汽车行驶的总公里数最少。

为此,他们愿意通过很多人挤在同一辆车的方式,来减少汽车行驶的总花销。

由此,他们可以很多人驾车到某一个兄弟的家里,然后所有人都钻进一辆车里,再继续前进。

公园的停车场能停放的车的数量有限,而且因为公园有入场费,所以一旦一辆车子进入到公园内,就必须停在那里,不能再去接其他人。

现在请你想出一种方法,可以使得他们全都到达公园的情况下,所有汽车行驶的总路程最少。

输入格式

第一行包含整数n,表示人和人之间或人和公园之间的道路的总数量。

接下来n行,每行包含两个字符串A、B和一个整数L,用以描述人A和人B之前存在道路,路长为L,或者描述某人和公园之间存在道路,路长为L。

道路都是双向的,并且人数不超过20,表示人的名字的字符串长度不超过10,公园用“Park”表示。

再接下来一行,包含整数s,表示公园的最大停车数量。

你可以假设每个人的家都有一条通往公园的道路。

输出格式
输出“Total miles driven: xxx”,其中xxx表示所有汽车行驶的总路程。

样例

样例输入
10
Alphonzo Bernardo 32
Alphonzo Park 57
Alphonzo Eduardo 43
Bernardo Park 19
Bernardo Clemenzi 82
Clemenzi Park 65
Clemenzi Herb 90
Clemenzi Eduardo 109
Park Herb 24
Herb Eduardo 79
3
样例输出
Total miles driven: 183

题解

这道题思路比较好想,但有点难打(细节巨多)。

首先题意可以转化为:给定一张n个点,m条边的无向图,求出一颗最小生成树,满足1号节点的度数不超过给定整数s。

1.我们先将名字用map转化为节点,用邻接表储存。

2.去掉1号节点,跑一个Kruskal,让离1号节点近的当根节点,注意用vis标记哪些边在树上,这样得到一个森林,每一棵树都为最小生成树,共有t棵树。

3.dfs找到每棵树中每个点到根节点的路径上最长边用结构体记录(每棵树从根节点dfs,只找一次)。

4.接着枚举每一个根节点,将其与1号连接(注意更新答案和vis)。

5.再考虑从每棵树根节点出发的每条不在树上的边(1,x)边权为z,运用之前找到的每条路径上的最长边(u,v),边权为w。从节点2至n枚举,最小化(z,w),若(z-w)> 0,则用(1,x)替换(u,v)。记住用dfs从x开始更新,vis也要更新。

6.第五条重复s-t次或w-z<0。

#include<bits/stdc++.h>
using namespace std;
const int M=1e3+5;
int ans,n,cnt,tot,k;
int fa[M],vis[M][M],d[M][M];
struct edge{int u,v,w;edge(){}edge(int V,int W){v=V;w=W;}
}p[M],t[M];
void Makeset(){for(int i=1;i<=tot;i++){fa[i]=i;}
}
int Findset(int x){if(fa[x]!=x){fa[x]=Findset(fa[x]);}return fa[x];
}
void Unionset(int u,int v){if(d[u][1]<d[v][1]){fa[v]=u;}else {fa[u]=v;}}
bool cmp(edge e1,edge e2){return e1.w<e2.w;}
void init(){char s1[20],s2[20];int U,V,W;map<string,int> name;	map<string,int>::iterator it1,it2;name["Park"]=++tot;//转化成数字memset(d,0x3f,sizeof(d));	scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%s %s %d",&s1,&s2,&W);it1=name.find(s1);it2=name.find(s2);if(it1!=name.end())U=it1->second;//出现过else {name[s1]=++tot;//第一次出现U=tot;}if(it2!=name.end())V=it2->second;else {name[s2]=++tot;V=tot;}p[++cnt].u=U;p[cnt].v=V;p[cnt].w=W;d[U][V]=W,d[V][U]=W;//邻接表}	scanf("%d",&k);
}
void Kruskal(){//板子Makeset();sort(p+1,p+cnt+1,cmp);for(int i=1;i<=cnt;i++){if(p[i].u==1||p[i].v==1) {continue;}int x1=Findset(p[i].u);int x2=Findset(p[i].v);if(x1!=x2){vis[p[i].u][p[i].v]=1,vis[p[i].v][p[i].u]=1;//注意记录vis      	Unionset(x1,x2);ans+=p[i].w;}}
}
void dfs(int now,int last,int u,int v){for(int i=2;i<=tot;i++){if(last!=i&&vis[now][i]){//在树上且不重复if(last==-1||d[now][i]>d[u][v]){//找最长的边t[i].u=now,t[i].v=i,t[i].w=d[now][i];dfs(i,now,now,i);	}else {			t[i].u=u,t[i].v=v,t[i].w=d[u][v];dfs(i,now,u,v);}}		}
}
void work(){memset(vis,0,sizeof(vis));Kruskal();for(int i=2;i<=tot;i++){if(fa[i]==i)//每棵树只找一次,从根节点开始找dfs(i,-1,-1,-1);}for(int i=2;i<=tot;i++){if(fa[i]==i) {//将每棵树连接节点1k--;//节点1剩余度数减少ans+=d[1][i];//更新答案fa[i]=1;vis[1][i]=1,vis[i][1]=1;//更新vis}}while(k--){//还有k点度数可用int ex,_ans=0;for(int i=2;i<=tot;i++){if(d[1][i]==0x3f3f3f3f||vis[1][i]==1){//无边或在树上continue;}			if(_ans<t[i].w-d[i][1]){//求最小_ans=t[i].w-d[i][1];ex=i;}}if(_ans==0) break;//已最优ans-=_ans;vis[1][ex]=1,vis[ex][1]=1;//删边,加边vis[t[ex].u][t[ex].v]=0,vis[t[ex].v][t[ex].u]=0;dfs(ex,1,-1,-1);//从ex开始更新最长路径}printf("Total miles driven: %d\n",ans);
}
int main(){init();work();   return 0;
}

http://www.ppmy.cn/news/286539.html

相关文章

郊游活动

题面&#xff1a; 有 n 名同学参加学校组织的郊游活动&#xff0c;已知学校给这 n 名同学 的郊游总经费为 A 元&#xff0c;与此同时第 i 位同学自己携带了 Mi 元。为了方便郊 游&#xff0c;活动地点提供 B(≥n)辆自行车供人租用&#xff0c;租用第 j 辆自行车的价格为 Cj 元…

bzoj1648: [Usaco2006 Dec]Cow Picnic 奶牛野餐

1648: [Usaco2006 Dec]Cow Picnic 奶牛野餐 Time Limit: 5 Sec Memory Limit: 64 MB Submit: 514 Solved: 316 [ Submit][ Status][ Discuss] Description The cows are having a picnic! Each of Farmer Johns K (1 < K < 100) cows is grazing in one of N (1 <…

产品要新意更要“全套解决方案”!山姆让露营玩出“风格”

文丨熔财经 作者|一城 横扫郊野、趋之若鹜&#xff0c;露营的突然火爆催生了露营经济学。从场地服务&#xff0c;到露营用具&#xff0c;再到吃喝玩乐&#xff0c;大量的市场机遇集中涌现&#xff0c;而户外品牌、电商平台等等&#xff0c;想要沾一沾露营热度的企业数不胜数。…

北京野外烧烤

呵呵,上庄我去过好几次啦,很不错啊. 如果是班里出去玩建议你先统计人数,十人以上就租车去吧,在颐和园北十五公里,不过我们都是坐车去的,坐车也很方便,在农大或者颐和山庄换乘652或者303路车到上庄水库站即可到达,下了车往回走一点就是水库了,过桥后的那个路口往前,走八百米有一…

野餐计划

题目 大佬讲解 这个是算法进阶指南上面的题目&#xff0c;ACwing上面的秦大佬讲的很详细 #include <bits/stdc.h> using namespace std; const int N1010; #define quick() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)//读入优化 #define mem(a,b) memset(a,b,…

蔬菜视觉分拣机器人的设计与实现(RoboWork参赛方案)

蔬菜视觉分拣机器人的设计与实现 本文参加新星计划人工智能(Pytorch)赛道&#xff1a;https://bbs.csdn.net/topics/613989052 文章目录 蔬菜视觉分拣机器人的设计与实现1. 技术栈背景2. 整体设计3. 机械结构3.1 整体结构3.2 底座结构3.3 小臂结构3.4 大臂结构3.5 负载组件结…

野餐规划

一群小丑演员&#xff0c;以其出色的柔术表演&#xff0c;可以无限量的钻进同一辆汽车中&#xff0c;而闻名世界。现在他们想要去公园玩耍&#xff0c;但是他们的经费非常紧缺。他们将乘车前往公园&#xff0c;为了减少花费&#xff0c;他们决定选择一种合理的乘车方式&#xf…

露营野餐

周六跟儿子约好的公园露营野餐&#xff0c;带上行装&#xff0c;简单的食物我们出发了。兴隆公园&#xff0c;朝阳公园&#xff0c;奥体森林公园三选一&#xff0c;兴隆公园太小&#xff0c;奥体太远&#xff0c;所以敲定坐标朝阳公园。 今天天气很好&#xff0c;蓝天白云&…