UVa1218完美的服务

题意:

在这里插入图片描述

思路:

在这里插入图片描述
在这里插入图片描述

注意:

  1. d[u][2]不能设为真的无穷大,因为涉及累加,会溢出。应该设一个它可能取到的最大值n。
  2. 然后就是,刚开始用vis数组标记,模拟dfs来遍历树,发现不行,因为在求d[u][2]的时候之前的孩子节点已经被标记访问过了,导致d[u][2]根本算不了,应该在参数列表加一个参数表示父节点。
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;

const int N = 1e5+5;
vector<int> G[N];

int d[N][3],  n;

void solve(int u, int dad){
	//printf("%d ",u);
	//vis[u] = 1;
	d[u][0] = 1; d[u][1] = 0;  
	d[u][2] = n; // d[u][2]是不可能状态,否则叶子节点没有服务器相连了,置为无穷大。 
	
	int k = G[u].size();
	if(k == 0){
		d[u][2] = 0; return;
	}
	for(int i = 0; i < k; ++i){
		int s = G[u][i];
		if(s == dad) continue;
		solve( s, u );
		// 选 u , 子可选可不选,选代价最少的
		d[u][0] += min(d[s][0], d[s][1]); 
		// 不选 u
		d[u][1] += d[s][2]; // 如果u的父亲被选了,那么u的儿子都不能选
		//d[u][2] += min();  
	}
	for(int i = 0; i < k; ++i){
		int s = G[u][i];
		if(s == dad) continue;
		d[u][2] = min(d[u][2], d[u][1] + d[s][0] - d[s][2]) ;// 如果u和u的父亲都没被选,那么u的儿子当中一定要有且仅有1个被选。
	}
	
}

int main()
{

	//freopen("in.txt","r",stdin);
	while(scanf("%d",&n) == 1&&n){
		for(int i = 1; i <= n; ++i) G[i].clear();
		//memset(vis,0,sizeof(vis));
		memset(d,0,sizeof(d));
		
		for(int i = 0; i < n-1; ++i){
			int a,b; scanf("%d %d",&a,&b);
			G[b].push_back(a); G[a].push_back(b);
		}
		
		solve(1,-1);
		printf("%d\n",min(d[1][0],d[1][2]));
		
		int e; scanf("%d",&e);
		if(e == -1) break;
	}

	return 0;
}

猜你喜欢

转载自blog.csdn.net/CY05627/article/details/88550063