IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 换根dp 洛谷+upc -> 正文阅读

[数据结构与算法]换根dp 洛谷+upc

题目描述

有一个村庄居住着 nn 个村民,有 n-1n?1 条路径使得这 nn 个村民的家联通,每条路径的长度都为 11。现在村长希望在某个村民家中召开一场会议,村长希望所有村民到会议地点的距离之和最小,那么村长应该要把会议地点设置在哪个村民的家中,并且这个距离总和最小是多少?若有多个节点都满足条件,则选择节点编号最小的那个点。

输入格式

第一行,一个数 nn,表示有 nn 个村民。

接下来 n-1n?1 行,每行两个数字 aa 和 bb,表示村民 aa 的家和村民 bb 的家之间存在一条路径。

输出格式

一行输出两个数字 xx 和 yy。

xx 表示村长将会在哪个村民家中举办会议。

yy 表示距离之和的最小值。

输入输出样例

输入 #1复制

4
1 2 
2 3 
3 4 

输出 #1复制

2 4

说明/提示

数据范围

对于 70\%70% 数据 n \le 10^3n≤103。

对于 100\%100% 数据 n \le 5 \times 10^4n≤5×104。

#include<bits/stdc++.h>
using namespace std;
const int N=5e4+5;
int d[N];//为根为1时服务
int f[N];//dp时的核心
int n,cnt;
int size[N];//子树中包括自己节点的个数
bool vis[N];
int head[N];
struct Edge
{
    int to,nxt;
} edge[N<<1];
void add(int x,int y)
{
    edge[++cnt].to=y;
    edge[cnt].nxt=head[x];
    head[x]=cnt;
}
void dfs1(int now,int fa)
{
    size[now]=1;
    for(int i=head[now]; i; i=edge[i].nxt)
    {
        int to=edge[i].to;
        if(to==fa) continue;//已经算过的点不要
        d[to]=d[now]+1;
        dfs1(to,now);
        size[now]+=size[to];
    }
}
void dfs(int now,int fa)
{
    f[now]=f[fa]+n-2*size[now];//树形dp核心部分
    for(int i=head[now]; i; i=edge[i].nxt)
    {
        int to=edge[i].to;
        if(to==fa) continue;
        dfs(to,now);
    }
}
signed main()
{
    scanf("%d",&n);
    for(int x,y,i=1; i<n; i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y);
        add(y,x);
    }
    d[1]=1;
    dfs1(1,-1);
    int maxn=0,idx=1;
    for(int i=1; i<=n; i++) maxn+=d[i];
    maxn-=n;
    f[1]=maxn;
    for(int i=head[1]; i; i=edge[i].nxt)
    {
        int to=edge[i].to;
        dfs(to,1);
    }
    for(int i=2; i<=n; i++)
    {
        if(f[i]<maxn) maxn=f[i],idx=i;
    }
    printf("%d %d",idx,maxn);
    return 0;
}

BLUESKY007喜欢种树。一天,她得到了一棵nn个点的树,其中节点ii重量为wiwi?。在种树之前,BLUESKY007需要用起重机把树吊起。由于她只有一台起重机,所以她只能选择一个点作为受力点。根据BLUESKY007所在世界的物理知识,吊起一棵树需要做的功为∑ni=1wi?disi∑i=1nwi?disi,其中disidisi表示节点ii与受力点之间的距离(边数)。

由于吊起这棵树的费用与所做的功正相关,所以BLUESKY007希望所做的功尽可能小。请你帮助她求出吊起这棵树所做的功的最小值。

题解

本题是裸的换根DP,很好实现。设以1为根结点,dep[u]表示u到根的路径长度,size[u]表示以u为根的子树中所有结点的重量和,当以1为根结点时,dfs一遍求出总做功的值,即sum=∑w[u]?dep[u]sum=∑w[u]?dep[u]。接着考虑换根带来的影响,当根从u换到儿子结点v时,v所在的子树少做功size[v],v外的结点多做功size[1]-size[v],即sum′=sum?size[v]+(size[1]?size[v])=sum?2?size[v]+size[1]sum′=sum?size[v]+(size[1]?size[v])=sum?2?size[v]+size[1]。
要使sum′≤sumsum′≤sum,则sum?2?size[v]+size[1]≤sumsum?2?size[v]+size[1]≤sum,即size[1]≤2?size[v]size[1]≤2?size[v],所以在换根时,只有满足2?size[v]≥size[1]2?size[v]≥size[1]的儿子结点v才可能使得总做功值变小,可以利用这个条件进行剪枝。

#include<bits/stdc++.h>
using namespace std;
const int N=2*1e5+5;
int n,w[N];
long long size[N],dep[N],sum,ans=1e18;
vector<int> g[N];
void dfs(int u,int fa){
	sum+=w[u]*dep[u];
	size[u]=w[u];
	for(int i=0;i<g[u].size();i++){
		int v=g[u][i];
		if(v==fa)continue;
		dep[v]=dep[u]+1;
		dfs(v,u);
		size[u]+=size[v];
	}
}
void change_root(int u,int fa,long long sum){
	ans=min(ans,sum);
	for(int i=0;i<g[u].size();i++){
		int v=g[u][i];
		if(v==fa)continue;
		long long tmp=sum-2*size[v]+size[1];
		if(2*size[v]>=size[1])change_root(v,u,tmp);
	}
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&w[i]);
	}
	for(int i=1,u,v;i<n;i++){
		scanf("%d %d",&u,&v);
		g[u].push_back(v);
		g[v].push_back(u);
	}
	dfs(1,-1);
	change_root(1,-1,sum);
	printf("%lld",ans);
}

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-03-24 00:48:42  更:2022-03-24 00:50:36 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 11:31:23-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码