Perfect Service UVA - 1218  树上的动态规划

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iomanip>
#include<assert.h>
#include<vector>
#include<list>
#include<map>
#include<set>
#include<sstream>
#include<stack>
#include<queue>
#include<string>
#include<bitset>
#include<algorithm>
#pragma warning(disable:4996)
#define me(s)  memset(s,0,sizeof(s))
#define _for(i,a,b) for(int i=(a);i<(b);++i)
#define _rep(i,a,b) for(int i=(a);i<=(b);++i)
using namespace std;
const int maxn = 10000 + 5;
const int INF = 1000000000;
vector<int> G[maxn], vertices;
int p[maxn], d[maxn][3];
void dfs(int u, int fa) {
	vertices.push_back(u);
	p[u] = fa;
	for (int i = 0; i < G[u].size(); i++) {
		int v = G[u][i];
		if (v != fa) dfs(v, u);
	}
}
int main() {
	int n;
	while (scanf("%d", &n) == 1) {
		for (int i = 0; i < n; i++) G[i].clear();
		for (int i = 0; i < n - 1; i++) {
			int u, v;
			scanf("%d%d", &u, &v); u--; v--;
			G[u].push_back(v);
			G[v].push_back(u);
		}
		vertices.clear();
		dfs(0, -1);         //无根树转为有根树,vertices其实存储的是对有根树先序遍历的结果
	    //状态分类: d(u,0) u是服务器,则子节点可以是服务器也可以不是,父节点也一样
		//d(u,1) u不是服务器,而u的父亲是服务器,那么u不能再跟别的服务器相连,因此u的所有子节点都不是服务器
		//d(u,2) u和u的父亲都不是服务器,那么u只能跟u的某一个子节点相连,也就是子节点中有且只有一个服务器
		//状态转移方程  d(u,0)=sum{min(d(v,0),d(v,1))|v是u的子节点} 
		//d(u,1)=sum{d(v,2)|v是u的子节点}
		//d(u,2)={min(d(u,1)-d(v,2)+d(v,0))|v是u的子节点
		//很显然所有的节点都依赖于它的子节点的信息,所以采用自底向下的方法计算
		//当然也可以采用递归的写法
		
		//非递归写法
 		for (int i = vertices.size() - 1; i >= 0; i--) {       //因为先序遍历,所以直接逆着算,一旦算到不是叶子的节点,它的所有子节点的信息也已经计算完了
			int u = vertices[i];
			d[u][0] = 1; d[u][1] = 0;                 //是不是服务器,先把自己加上
			for (int j = 0; j < G[u].size(); j++) {
				int v = G[u][j];
				if (v == p[u]) continue;               //只要子节点
				d[u][0] += min(d[v][0], d[v][1]); 
				d[u][1] += d[v][2]; 
				if (d[u][0] > INF) d[u][0] = INF; //防止爆int
				if (d[u][1] > INF) d[u][1] = INF;
			}
			d[u][2] = INF;                 
			//对于叶节点来说,它或者它的父节点必须有一个是服务器,所以它的d(u,2)是不存在的,
			//所以这里初始化赋值为inf,从而后面算的时候取优的过程中会被抛弃
			for (int j = 0; j < G[u].size(); j++) {
				int v = G[u][j];
				if (v == p[u]) continue;
				d[u][2] = min(d[u][2], d[u][1] - d[v][2] + d[v][0]); 
			}
		}
		printf("%d\n", min(d[0][0], d[0][2]));
		scanf("%d", &n); 
	}
}

猜你喜欢

转载自blog.csdn.net/qq_41776911/article/details/82772688