Acwing 5475. 聚会【多源bfs】

2024-02-25 19:44
文章标签 bfs acwing 多源 聚会 5475

本文主要是介绍Acwing 5475. 聚会【多源bfs】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

原题链接:https://www.acwing.com/problem/content/5478/

题目描述:

约翰的农场有 n 个谷仓,编号 1∼n,谷仓之间有 m 条双向道路。

所有道路的长度均为 1。

奶牛们可以通过这些道路从任意谷仓到达任意其它谷仓。

任意两个谷仓之间最多只包含一条道路(注意是道路,不是路径)。

不存在道路两端都连接同一个谷仓的情况。

农场中一共有 k 种干草,编号 1∼k。

每个谷仓都存有一种干草,其中第 i 个谷仓存有第 ai 种干草。

每种干草都至少存在于一个谷仓中。

奶牛们计划选择一个谷仓举办干草宴会。

为了让宴会足够丰盛,至少需要将 s 种不同的干草汇集在宴会谷仓。

宴会谷仓本身就包含一种干草,而其它干草就需要从其它谷仓运输。

已知,将一种干草从一个谷仓运至另一个谷仓所需的运输成本等于两谷仓之间的最短路径距离。

请你帮助奶牛们计算,对于每个谷仓,如果挑选其为宴会举办地,则举办宴会需要付出的总运输成本的最小可能值是多少。

输入输出描述:

输入格式

第一行包含四个整数 n,m,k,s。

第二行包含 n 个整数 a1,a2,…,an。

接下来 m 行,每行包含两个整数 u,v,表示第 u 个谷仓和第 v 个谷仓之间存在一条双向道路。

输出格式

共一行,输出 n 个整数,其中第 i 个整数表示在第 i个谷仓举办宴会需要付出的总运输成本的最小可能值。

数据范围

前 3 个测试点满足 1≤n≤10。
所有测试点满足 1≤n≤10^5,0≤m≤10^5,1≤s≤k≤min(n,100),1≤ai≤k,1≤u,v≤n,u≠v。

输入样例1:
5 5 4 3
1 2 4 3 2
1 2
2 3
3 4
4 1
4 5
输出样例1:
2 2 2 2 3
输入样例2:
7 6 3 2
1 2 3 3 2 2 1
1 2
2 3
3 4
2 5
5 6
6 7
输出样例2:
1 1 1 2 2 1 1

解题思路:

很久没用多源bfs这个算法了,所以根本就没有往这个算法上想,有一些算法还是需要及时复习复习呀,防止忘记,首先这个题目最暴力的做法就是对每一个点跑一边bfs,但是这个做法时间复杂度是O(n^2),这个题目n=1e5,这个时间复杂度肯定会tle,但是我们可以发现k=100非常小,也就是干草的种类非常少,我们不妨对每一种干草跑一边bfs,记录每一种干草到所有点的最短距离,也就是说每次bfs有多个起点,这不就是多源bfs吗,最多只有100种干草,所以最多只会跑100遍多源bfs,bfs过程时间为O(n*100),大概是1e7,然后每一个点都记录了各种干草到这个点的最短距离,对于每一个点我们需要取到k种干草中距离最短的s种,就是每一个点应该输出的答案,所以对于每一个点的k种干草的距离我们需要从小到大排序,时间复杂度为O(n*k*log(k)),大概1e5*100*log(100),这个时间是勉强可以过的,但是这个题目会卡常,我们在每次多源bfs中不要使用stl中的队列,使用stl中的队列会tle,可以换成数组模拟队列,换成数组模拟就可以过了。

时间复杂度:O(n*klog(k))。

空间复杂度:O(n*100),n表示点的个数。

cpp代码如下:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>using namespace std;
typedef long long LL;const int N=1e5+10,M=N*2;int n,m,k,s;
int a[N];
int d[N],q[N];
int ans[N][110];  //ans[i][j]表示第j种干草到点i的最短距离
int h[N],e[M],ne[M],idx;void add(int a,int b)
{e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}void bfs(int type)
{memset(d,0x3f,sizeof d);int hh=0,tt=-1;for(int i=1;i<=n;i++)if(a[i]==type)q[++tt]=i,d[i]=0;  //多源bfs,会有多个起点while(hh<=tt){auto t=q[hh++];for(int i=h[t];i!=-1;i=ne[i]){int j=e[i];if(d[j]>d[t]+1){d[j]=d[t]+1;q[++tt]=j;}}}for(int i=1;i<=n;i++){ans[i][type]=d[i];}}
int main()
{cin>>n>>m>>k>>s;for(int i=1;i<=n;i++)scanf("%d",&a[i]);memset(h,-1,sizeof h);for(int i=0;i<m;i++){int u,v;scanf("%d%d",&u,&v);add(u,v),add(v,u);}//对于每一种干草跑一边多源bfs,记录每一种干草到各个点的最短距离for(int i=1;i<=k;i++)bfs(i);//对于每一个点需要拿到距离最短的s种干草的距离,所以这里进行排序for(int i=1;i<=n;i++)sort(ans[i]+1,ans[i]+1+k);for(int i=1;i<=n;i++){LL res=0;for(int j=1;j<=s;j++)res+=ans[i][j];  printf("%lld ",res);}return 0;
}

这篇关于Acwing 5475. 聚会【多源bfs】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/746506

相关文章

hdu1254(嵌套bfs,两次bfs)

/*第一次做这种题感觉很有压力,思路还是有点混乱,总是wa,改了好多次才ac的思路:把箱子的移动当做第一层bfs,队列节点要用到当前箱子坐标(x,y),走的次数step,当前人的weizhi(man_x,man_y),要判断人能否将箱子推到某点时要嵌套第二层bfs(人的移动);代码如下:

poj 2195 bfs+有流量限制的最小费用流

题意: 给一张n * m(100 * 100)的图,图中” . " 代表空地, “ M ” 代表人, “ H ” 代表家。 现在,要你安排每个人从他所在的地方移动到家里,每移动一格的消耗是1,求最小的消耗。 人可以移动到家的那一格但是不进去。 解析: 先用bfs搞出每个M与每个H的距离。 然后就是网络流的建图过程了,先抽象出源点s和汇点t。 令源点与每个人相连,容量为1,费用为

POJ 3057 最大二分匹配+bfs + 二分

SampleInput35 5XXDXXX...XD...XX...DXXXXX5 12XXXXXXXXXXXXX..........DX.XXXXXXXXXXX..........XXXXXXXXXXXXX5 5XDXXXX.X.DXX.XXD.X.XXXXDXSampleOutput321impossible

深度优先(DFS)和广度优先(BFS)——算法

深度优先 深度优先搜索算法(英语:Depth-First-Search,DFS)是一种用于遍历或搜索树或图的算法。 沿着树的深度遍历树的节点,尽可能深的搜索树的分支,当节点v的所在边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访

【AcWing】851. 求最短路

spfa算法其实是对贝尔曼福特算法做一个优化。 贝尔曼福特算法会遍历所有边来更新,但是每一次迭代的话我不一定每条边都会更新,SPFA是对这个做优化。 如果说dist[b]在当前这次迭代想变小的话,那么一定是dist[a]变小了,只有a变小了,a的后继(b)才会变小。 用宽搜来做优化,用一个队列,队列里边存的就是所有变小了的结点(队列里存的是待更新的点)。 基本思路就是我更新过谁,我再拿

双头BFS

牛客月赛100 D题,过了80%数据,调了一下午。。。烦死了。。。 还是没调试出来,别人的代码用5维的距离的更新有滞后性,要在遍历之前要去重。。。 #include<bits/stdc++.h>using namespace std;const int N=2e3+10;char g[N][N];int dis[N][N],d1[N][N];int n,m,sx,sy;int dx

Knight Moves -uva 简单的BFS遍历

昨天刚学了BFS的遍历,在uva上找了个题敲了出来,感觉还不错,最近敲代码挺有手感的,希望这种状态保持下去 #include<iostream>#include<stdio.h>#include<stdlib.h>#include<string.h>#define MAX_SIZE 10 + 5#define LEN 100 + 10using namespace std;in

【CF】D. Arthur and Walls(BFS + 贪心)

D题 解题思路就是每次检查2X2的方格里是否只有一个‘*’,如果有的话这个*就需要变成‘.’,利用BFS进行遍历,入队的要求是这个点为. 一开始将所有的'.'全部加入队列,如果碰到一个'*'变成'.'就入队,判断的时候从4个方向就行判断 题目链接:http://codeforces.com/contest/525/problem/D #include<cstdio>#include<

【AcWing】852. spfa判断负环

#include<iostream>#include<algorithm>#include<cstring>#include<queue>using namespace std;const int N= 1e5+10;int n,m;int h[N],w[N],e[N],ne[N],idx;int dist[N],cnt[N];//cnt存最短路径的边数bool st[N];v

hdu2717(裸bfs广搜)

Catch That Cow Time Limit: 5000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 7304 Accepted Submission(s): 2308 题目链接: http://acm.hdu.edu.cn/showproblem.