CF 986A Fair——多源bfs

题目:http://codeforces.com/contest/986/problem/A

此题乍一看没什么不T的思路...

发现边权是1,bfs?

考虑朴素的想法,遍历所有的点,bfs,过程中更新出各种商品的最短路,然后排序加和……

好像很不行,似乎有一大堆冗余的东西,主要因为每个点上只有一种商品啊;

不妨干脆换个思路,不是找每个点到每种商品的距离,而是找每种商品到每个点的距离,如何?

一种商品存在于多个点上,可以进行多源 bfs!

也就是 bfs 一开始的时候把多个点加进优先队列里,复杂度 n*k;

所以以后遇到正着做很麻烦问题,不妨反过来考虑一下。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
int const maxn=1e5+5;
int n,m,k,s,dis[maxn][105],hd[maxn],ct;
vector<int>v[105];
queue<int>q;
struct N{
    int to,nxt;
    N(int t=0,int n=0):to(t),nxt(n) {}
}ed[maxn<<1];
void add(int x,int y){ed[++ct]=N(y,hd[x]); hd[x]=ct;}
int main()
{
    scanf("%d%d%d%d",&n,&m,&k,&s);
    memset(dis,0x3f,sizeof dis);
    for(int i=1,x;i<=n;i++)
    {
        scanf("%d",&x); dis[i][x]=0;
        v[x].push_back(i);
    }
    for(int i=1,x,y;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y); add(y,x);
    }
    for(int i=1;i<=k;i++)
    {
        while(q.size())q.pop();
        for(int j=0;j<v[i].size();j++)q.push(v[i][j]);
        while(q.size())
        {
            int x=q.front(); q.pop();
            for(int j=hd[x],u;j;j=ed[j].nxt)
            {
                if(dis[u=ed[j].to][i]>dis[x][i]+1)
                    dis[u][i]=dis[x][i]+1,q.push(u);
            }
        }
    }
    for(int i=1;i<=n;i++)
    {
        int sum=0;
        sort(dis[i]+1,dis[i]+k+1);
        for(int j=1;j<=s;j++)sum+=dis[i][j];
        printf("%d ",sum);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Zinn/p/9275485.html

时间: 2024-09-29 22:45:14

CF 986A Fair——多源bfs的相关文章

bzoj 2252 [ 2010 Beijing wc ] 矩阵距离 —— 多源bfs

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2252 又没能自己想出来... 一直在想如何从每个1开始广搜更新答案,再剪剪枝,什么遇到1就不走了... 然而实际上直接多源bfs,从所有1一起开始,因为只需要找到0碰到的第一个1即可: 这样搜一遍就可以,复杂度很美. 代码如下: #include<iostream> #include<cstdio> #include<cstring> #include<al

多源bfs

https://codeforces.com/contest/1283/problem/D 题意:在一条无限长的坐标轴上,给你n颗树,m个人.求所有人到树的最短距离的总和和坐标. 解法:多源bfs,map标记. //#include <bits/stdc++.h> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <iost

CodeForces - 986A Fair (BFS+贪心)

题意:有N个点M条边的无向图,每个点有给定的ai(1<=ai<=K,K<=200)表示该点拥有的物品编号,保证1-K在N个点全部出现.求每个点收集S个不同的物品所要走过的最短路程(边的长度为1). 分析:N是1e5,如果直接对每个点搜索肯定超时.发现K的范围很小,而且1-K全部覆盖.那么考虑对所有1-K的值BFS,用一个二维数组dp[i][j]记录i点要获取编号为j的物品最少走过的路程,并对每个点取最小的S个物品对应的路径. #include<bits/stdc++.h> u

CF #375 (Div. 2) D. bfs

1.CF #375 (Div. 2)  D. Lakes in Berland 2.总结:麻烦的bfs,但其实很水.. 3.题意:n*m的陆地与水泽,水泽在边界表示连通海洋.最后要剩k个湖,总要填掉多少个湖,然后输出. #include<bits/stdc++.h> #define F(i,a,b) for (int i=a;i<b;i++) #define FF(i,a,b) for (int i=a;i<=b;i++) #define mes(a,b) memset(a,b,s

F. Super Jaber (多源BFS)

题目:传送门 题意: 有n * m个城市,每个城市都有一个颜色,共有 k 种颜色,也就是每个城市的颜色只能是 1 ~ k 的某个数字.      然后,有q次询问,每次询问给你 x1, y1, x2, y2:问你从(x1, y1)到(x2, y2)的最少操作数.      操作有两种: 1. 你可以移动到你当前位置的上下左右,只要不越界.       2.你可以移动到任意和你当前所在的位置颜色相同的位置. 1 <= n, m <= 1000,  k <= min(40, n * m):

uva 11624 Fire!(多源BFS)

uva 11624 Fire! 题目大意:J在迷宫里工作,有一天迷宫起火了,火源有多处.每过一秒,火源都会向四个方向蔓延,J也会向四个方向移动,问J能不能跑出去,能的话输出他跑出去的最短时间,否则输出"IMPOSSIBLE" 解题思路:先进行一次BFS,找出每一点火焰蔓延到该处的最短时间.然后根据这张"火势图",对J的行进路线进行BFS.注意J在边缘的时候,以及没有火源的时候. #include <cstdio> #include <cstring

cf刷枪软件生成器源码

软件介绍:只要输入你的QQ号码就可以做出属于你自己的刷枪,刷钻软件再也不用去羡慕别人软件作者QQ:646234584] 让我们一起来卖CF外挂赚大钱吧,这软没什么用就只可以赚钱而已!! 软件的豪华界面,请往下看!! 生成器界面 生成的刷钻软件界面 大家看看我用这软件赚了多少QB 大家看看我用这软件赚了多少QB 大家看看我用这软件赚了多少QB 联系QQ646234584 下载地址:http://www.ronkui.com/wyscq/%E5%8D%96CF%E5%A4%96%E6%8C%82%E

C. Ice Cave (CF #301 (Div. 2) 搜索bfs)

C. Ice Cave time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output You play a computer game. Your character stands on some level of a multilevel ice cave. In order to move on forward, you need to

CF D. Fair(思维+DFS)

http://codeforces.com/contest/987/problem/D 题目大概: 给出一个n个城镇m条边的图,给出每个城镇拥有的特产(可能多个城镇有相同特产).有k种不同特产. 要求每个城镇需要其他城镇运输特产到自己的城镇,每个城镇必须拥有s种特产,那么在城镇满足s种特产后,需要的最短路径是多长,最短路指的是特产运输过来走过的边的数量. 分析: 一开始以为是道水题,因为我只要对每个点都进行一次DFS,那问题就很简单了,但是...细想下,这其实是不行的,因为会TLE. 那现在我们