「题解」水库 reservoir

Posted Lu_Anlai

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了「题解」水库 reservoir相关的知识,希望对你有一定的参考价值。

本文将同步发布于:

题目

题目描述

R 国有 \\(n\\) 座城市和 \\(n-1\\) 条长度为 \\(1\\) 的双向道路,每条双向道路连接两座城市,城市之间均相互连通。

现在你需要维护 R 国的供水系统。你可以在一些城市修建水库,在第 \\(i\\) 个城市修建水库需要每年 \\(c_i\\) 的维护费用。对于没有修建水库的城市,如果离它最近的水库的距离为 \\(d\\),那么需要每年 \\(t_d\\) 的运输费用来保证该城市的用水需求。保证 \\(t_i\\) 严格递增。

你的任务是计算出每年所需要的最小花费。

\\(1\\leq n\\leq 10^3\\)\\(0\\leq c_i,t_i\\leq 10^5\\)

题解

很简单的树形动态规划。

\\(f_{i,j}\\) 表示,以 \\(i\\) 为根的子树,\\(i\\) 的供水依赖于 \\(j\\) 所需的最小花费,\\(g_i\\)\\(i\\) 的子树,不论 \\(i\\) 依赖于谁的最小花费。

那么我们有:

\\[f_{i,j}=t_{\\texttt{dis}_{i,j}}+c_j+\\sum_{k\\in\\texttt{son}_i}\\min\\{f_{k,j}-c_j,g_k\\} \\]

\\[g_i=\\min_{j=1}^n\\{f_{i,j}\\} \\]

直接动态规划即可,时间复杂度为 \\(\\Theta(n^2)\\)

参考程序

#pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
using namespace std;
#define reg register
typedef long long ll;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
static char buf[1<<21],*p1=buf,*p2=buf;
inline int read(void){
	reg char ch=getchar();
	reg int res=0;
	while(!isdigit(ch)) ch=getchar();
	while(isdigit(ch)) res=10*res+(ch^\'0\'),ch=getchar();
	return res;
}

inline int min(reg int a,reg int b){
	return a<b?a:b;
}

const int MAXN=1e3+5;
const int inf=0x3f3f3f3f;

int n;
int c[MAXN],t[MAXN];
vector<int> G[MAXN];
int dis[MAXN][MAXN];

inline void getDis(reg int u,reg int father,reg int rt,reg int dep){
	dis[rt][u]=dep;
	for(int v:G[u])
		if(v!=father)
			getDis(v,u,rt,dep+1);
	return;
}

int f[MAXN][MAXN];
int g[MAXN];

inline void dfs(reg int u,reg int father){
	for(reg int i=1;i<=n;++i)
		f[u][i]=t[dis[u][i]]+c[i];
	for(int v:G[u])
		if(v!=father){
			dfs(v,u);
			for(reg int i=1;i<=n;++i)
				f[u][i]+=min(f[v][i]-c[i],g[v]);
		}
	g[u]=inf;
	for(reg int i=1;i<=n;++i)
		g[u]=min(g[u],f[u][i]);
	return;
}

int main(void){
	n=read();
	for(reg int i=1;i<=n;++i)
		c[i]=read();
	for(reg int i=1;i<=n;++i)
		t[i]=read();
	for(reg int i=1;i<n;++i){
		static int s,t;
		s=read(),t=read();
		G[s].push_back(t),G[t].push_back(s);
	}
	for(reg int i=1;i<=n;++i)
		getDis(i,0,i,0);
	dfs(1,0);
	printf("%d\\n",g[1]);
	return 0;
}

以上是关于「题解」水库 reservoir的主要内容,如果未能解决你的问题,请参考以下文章

Reservoir Sampling - snapchat

Reservoir Sampling

Reservoir Sampling

Reservoir Sampling-382. Linked List Random Node

leetcode_398 Random Pick Index(Reservoir Sampling)

Spark MLlib之水塘抽样算法(Reservoir Sampling)