完美的服务 Perfect Service

在这里插入图片描述
UVA1218
定义 S o n [ i ] Son[i] Son[i]为第 i i i个节点的子节点集
d p [ i ] dp[i] dp[i]为以 i i i为根节点的最少服务器需求量

  1. d p [ i ] [ 0 ] dp[i][0] dp[i][0]为将第 i i i个节点作为服务器的时的情况,即它的子节点既可以是服务器,又可以是客户端。
  2. d p [ i ] [ 1 ] dp[i][1] dp[i][1]为第 i i i个节点为客户端且它的父节点为服务器的情况,即它的子节点只能是客户端。(一个客户端只能且必须能和一个服务器直接相连)
  3. d p [ i ] [ 2 ] dp[i][2] dp[i][2]为第 i i i个节点为客户端且它的父节点也为客户端的情况,即i有且只有一个子节点是服务器。

转移方程
V V V i i i的子节点集合

  1. d p [ i ] [ 0 ] = ( ∑ v ∈ V m i n ( d p [ v ] [ 0 ] , d p [ v ] [ 1 ] ) ) + 1 dp[i][0]=(\sum\limits_{v\in V}{min(dp[v][0],dp[v][1])})+1 dp[i][0]=(vVmin(dp[v][0],dp[v][1]))+1
  2. d p [ i ] [ 1 ] = ∑ v ∈ V d p [ v ] [ 2 ] dp[i][1]=\sum\limits_{v\in V}{dp[v][2]} dp[i][1]=vVdp[v][2]
  3. d p [ i ] [ 2 ] = m i n ( d p [ v k ] [ 0 ] + ∑ v ∈ V − v k d p [ v ] [ 2 ] ) = m i n ( d p [ v k ] [ 0 ] + d p [ i ] [ 1 ] − d p [ v k ] [ 2 ] dp[i][2]=min(dp[v_k][0]+\sum\limits_{v\in {V-v_k}}{dp[v][2]})=min(dp[v_k][0]+dp[i][1]-dp[v_k][2] dp[i][2]=min(dp[vk][0]+vVvkdp[v][2])=min(dp[vk][0]+dp[i][1]dp[vk][2]
    即枚举 i i i的每一个子节点作为服务器的情况。

AC代码

#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#include<map>
using namespace std;
int N, Status;
vector<int> Son[10001];
int dp[10001][3];
void Clear() {
	for (int i = 1; i <= N; ++i) {
		Son[i].clear();
	}
}
void Input() {	
	cin >> N;
	Clear();
	for (int i = 1; i < N; ++i) {
		int x, y;
		cin >> x >> y;
		Son[x].push_back(y);
		Son[y].push_back(x);
	}
}
void DP(int Root,int Father) {
	dp[Root][0] = 1;
	dp[Root][1] = 0;
	dp[Root][2] = 10000;//inf
	for (auto SonIt = Son[Root].cbegin(); SonIt != Son[Root].cend(); ++SonIt) {
		if (*SonIt == Father) {
			continue;
		}
		DP(*SonIt, Root);
		dp[Root][0] += min(dp[*SonIt][0], dp[*SonIt][1]);
		dp[Root][1] += dp[*SonIt][2];
	}
	for (auto SonIt = Son[Root].cbegin(); SonIt != Son[Root].cend(); ++SonIt) {
		if (*SonIt == Father) {
			continue;
		}
		dp[Root][2] = min(dp[Root][2], dp[Root][1] - dp[*SonIt][2] + dp[*SonIt][0]);
	}
}
int main() {
	while (true) {
		Input();
		DP(1, -1);
		cout <<min(dp[1][0],dp[1][2]) << endl;
		cin >> Status;
		if (Status == -1) {
			break;
		}
	}
	return 0;
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值