牛客月赛8-病毒感染-(树的重心+性质)

2024-01-15 07:40

本文主要是介绍牛客月赛8-病毒感染-(树的重心+性质),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

A

题意:
就是给你一个图,然后这个图呢所有边权都是1,图的类型保证没有大小大于等于3的环。然后小A不知道自己在哪个点了,他只知道,自己所在的点到其余所有点的最短路径的和是最小的。现在问你小A在哪些点,请全部输出。

思考:
看到题目感觉应该是用到树上的啥性质了,如果用最短路的话,一般这种题做不了。然后看了题解发现,是用了树的重心这个性质,树的重心到其余所有点的权值和最小。然后求树的重心就行了,这里我们就要利用这个每个边都是1的特性了。我们采用dfs维护距离和的方法,假设当前节点是sum[x],我们要转移到sum[y],就有这么一条转移方程 sum[y]=sum[x]-cnt[y]+(n-cnt[y]).这个cnt[y]代表的是y这个节点的子树重量。从x到y这一步,y这个节点到y的子节点的距离全部都-1 故-cnt[y],同时不是子树的点,都+1,所以+(n-cnt[y])。那到了这一步,我们需要求出cnt数组了。我们假设刚开始以1为根,然后dfs回溯的时候算出cnt。最后再来一次dfs维护距离和,求出sum数组。问题就得到解决。
这里是一张树的重心的性质的图:在这里插入图片描述
同时呢,以前做过一道用树的直径性质的题目:巨木之森。这个题用到的性质就是,树上的点距离他最远的点就是他到这颗树的直径的两个端点的最大值。

代码:

直接维护出点到其他点最小值的做法:int T,n,m,k;
int minn = inf;
int va[N];
int dep[N],cnt[N],sum[N];vector<int > e[N];void get(int now,int p)
{dep[now] = dep[p]+1;cnt[now] = 1;for(auto spot:e[now]){if(spot==p) continue;get(spot,now);cnt[now] += cnt[spot];}	
}void dfs(int now,int p)
{for(auto spot:e[now]){if(spot==p) continue;sum[spot] = sum[now]-cnt[spot]+(n-cnt[spot]);dfs(spot,now);}minn = min(minn,sum[now]);
}signed main()
{IOS;cin>>n>>m;for(int i=1;i<=m;i++){int a,b;cin>>a>>b;e[a].pb(b);e[b].pb(a);}get(1,0);for(int i=1;i<=n;i++) sum[1] += dep[i];dfs(1,0);for(int i=1;i<=n;i++){if(sum[i]==minn)cout<<i<<" ";}return 0;
}树上get一遍求出重心,然后再从重心跑一遍spfa求出最小的总和:int T,n,m,k;
int zx,maxn = inf;
int dep[N],cnt[N],siz[N];
int dist[N],vis[N];vector<int > e[N];void get(int now,int p)
{dep[now] = dep[p]+1;cnt[now] = 1;for(auto spot:e[now]){if(spot==p) continue;get(spot,now);cnt[now] += cnt[spot];siz[now] = max(siz[now],cnt[spot]);}siz[now] = max(siz[now],n-cnt[now]);if(maxn>siz[now]) {zx = now;maxn = siz[now];}
}void spfa(int x)
{for(int i=1;i<=n;i++) dist[i] = inf;queue<int > q;q.push(x);dist[x] = 0;vis[x] = 1;while(q.size()){auto now = q.front();q.pop();vis[now] = 0;for(auto spot:e[now]){if(dist[spot]>dist[now]+1){dist[spot] = dist[now]+1;if(!vis[spot]){vis[spot] = 1;q.push(spot);}}}}
}signed main()
{IOS;cin>>n>>m;for(int i=1;i<=m;i++){int a,b;cin>>a>>b;e[a].pb(b);e[b].pb(a);}get(1,0);spfa(zx);int ans = 0;for(int i=1;i<=n;i++) ans += dist[i];cout<<ans<<"\n";return 0;
}

总结:
多多积累经验。

这篇关于牛客月赛8-病毒感染-(树的重心+性质)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

每日一题|牛客竞赛|四舍五入|字符串+贪心+模拟

每日一题|四舍五入 四舍五入 心有猛虎,细嗅蔷薇。你好朋友,这里是锅巴的C\C++学习笔记,常言道,不积跬步无以至千里,希望有朝一日我们积累的滴水可以击穿顽石。 四舍五入 题目: 牛牛发明了一种新的四舍五入应用于整数,对个位四舍五入,规则如下 12345->12350 12399->12400 输入描述: 输入一个整数n(0<=n<=109 ) 输出描述: 输出一个整数

牛客小白月赛100部分题解

比赛地址:牛客小白月赛100_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ A.ACM中的A题 #include<bits/stdc++.h>using namespace std;#define ll long long#define ull = unsigned long longvoid solve() {ll a,b,c;cin>>a>>b>

牛客小白月赛100(A,B,C,D,E,F三元环计数)

比赛链接 官方讲解 这场比较简单,ABC都很签到,D是个不太裸需要预处理的 B F S BFS BFS 搜索,E是调和级数暴力枚举,F是三元环计数。三元环考的比较少,没见过可能会偏难。 A ACM中的A题 思路: 就是枚举每个边变成原来的两倍,然后看看两短边之和是否大于第三边即可。 不能只给最短边乘 2 2 2,比如 1 4 8 这组数据,也不能只给第二短边乘 2 2 2,比

笔试强训,[NOIP2002普及组]过河卒牛客.游游的水果大礼包牛客.买卖股票的最好时机(二)二叉树非递归前序遍历

目录 [NOIP2002普及组]过河卒 牛客.游游的水果大礼包 牛客.买卖股票的最好时机(二) 二叉树非递归前序遍历 [NOIP2002普及组]过河卒 题里面给的提示很有用,那个马的关系,后面就注意,dp需要作为long的类型。 import java.util.Scanner;// 注意类名必须为 Main, 不要有任何 package xxx 信息publ

每日OJ_牛客_求和(递归深搜)

目录 牛客_求和(递归深搜) 解析代码 牛客_求和(递归深搜) 求和_好未来笔试题_牛客网 解析代码         递归中每次累加一个新的数,如果累加和大于等于目标,结束递归。此时如果累加和正好等于目标,则打印组合。向上回退搜索其它组合。此题本身就是一个搜索的过程,找到所有的组合。 #include <iostream>#include <cmath>#in

对极约束及其性质 —— 公式详细推导

Title: 对极约束及其性质 —— 公式详细推导 文章目录 前言1. 对极约束 (Epipolar Constraint)2. 坐标转换 (Coordinate Transformations)3. 像素坐标 (Pixel Coordinates)4. 像素坐标转换 (Transformations of Pixel Coordinates)5. 本质矩阵 (Essential Matr

牛客《剑指Offer》 -- 数值的整数次方

题目描述 给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。 思路 特别注意负数的情况,出现负数,将其转化为正数然后求倒数。 class Solution {public:double Power(double base, int exponent) {double total = 1;bool flag = false

牛客网《剑指Offer》 二进制中1的个数

题目描述 输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。 思路 负数用补码,其实就是求一个数据在计算机中是存储是怎么样子的。用位运算,就能很好实现。 class Solution {public:int NumberOf1(int n) {int count = 0;int flag = 1;while (flag != 0) {if ((n & f

牛客网《剑指Offer》 矩形覆盖

题目描述 我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法? class Solution {public:int rectCover(int number) {if(number==0) return 0;if(number==1) return 1;if(number==2) return 2;retu

牛客《剑指Offer》 变态跳台阶

题目描述 一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。 思路 根据 普通的跳台阶可以总结出 f(n) = f(n-1) + f(n-2) +f(n-3) + 。。。。+ f(1) +1 不妨设 f(0) = 1 , 则易得 class Solution {public:int jumpFloorII(int n