UVa 1220 Party at Hai-Bula(树形DP)

题目链接:http://arena.acmclub.com/problem.php?id=15595

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

public class Main {
	static int max = 200 + 10;
	static int[][] d = new int[max][2];// d[i][0]表示不选,d[i][1]表示选。
	// f[i][0]==1表示不选,且方案唯一,f[i][0]==0表示选、且方案不唯一。
	// f[i][1]==1表示选,且方案唯一,f[i][1]==0表示选、且方案不唯一。
	static int[][] f = new int[max][2];
	static ArrayList<Integer>[] sons = new ArrayList[max];
	static Map<String, Integer> dict;
	static int n;
	static int cnt;

	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		while (in.hasNextInt()) {
			n = in.nextInt();
			if (n == 0)
				break;
			cnt = 0;
			dict = new HashMap<String, Integer>();
			for (int i = 0; i < n; i++) {
				sons[i] = new ArrayList<Integer>();
			}
			String s = in.next();
			ID(s);
			for (int i = 0; i < n - 1; i++) {
				String s1 = in.next();// 下属
				String s2 = in.next();// 上司
				sons[ID(s2)].add(ID(s1));
			}
			int max0 = dp(0, 0);
			int max1 = dp(0, 1);
			System.out.print(Math.max(max0, max1) + " ");
			boolean unique = false;
			if (max1 > max0 && f[0][1] == 1)
				unique = true;
			if (max0 > max1 && f[0][0] == 1)//注意这里不是else if。
				unique = true;
			if (unique)
				System.out.println("Yes");
			else
				System.out.println("No");
		}
	}

	public static int ID(String s) {//这里运用与uva12186类似的方法
		if (dict.get(s) == null)//将上司(编号)的下属(编号)添加到上司所在的容器中。
			dict.put(s, cnt++);
		return dict.get(s);
	}

	public static int dp(int u, int k) {
		f[u][k] = 1;// 先默认设置为1,然后在后面的判断中,不满足条件,再改为0
		d[u][k] = k;// 选中为0,不选中为1,而0和1都是k值,故d[u][k] = k;
		for (int i = 0; i < sons[u].size(); i++) {
			int v = sons[u].get(i);// 上司u的下属v。
			if (k == 1) {
				d[u][1] += dp(v, 0);
				if (f[v][0] == 0)
					f[u][1] = 0;
			} else {
				int max0 = dp(v, 0);
				int max1 = dp(v, 1);
				d[u][0] += Math.max(max0, max1);
				if (max0 > max1 && f[v][0] == 0)
					f[u][0] = 0;
				else if (max1 > max0 && f[v][1] == 0)
					f[u][0] = 0;
				else if (max0 == max1)
					f[u][0] = 0;
			}
		}
		return d[u][k];
	}
}


题意:

    一个公司员工要举行聚会,公司里有n(n<=200)个人形成一个树状结构。要求任意一个人不能和他的直接上司同时到场,一个员工只有一个支系上司,现在求最多有多少人到场,并且方案是否唯一

分析:

    本题几乎就是树的最大独立集问题,不过多了一个要求:判断唯一性。设:

1,d(u,0)和f(u,0)表示以u为根的子树中,不选uhko 能得到的最大人数以及方案唯一性。(f(u,0)=1表示唯一,0表示不唯一)

2,d(u,1)和f(u,1)表示以u为根的子树中,选u点能得到的最大人数以及方案的唯一性。

相应地,状态转移方程也有两套。

1,d(u,1)的计算:因为选了u,所以u的子结点都不能选,因此d(u,1)=sum{d(v,0) | v是u的子结点}。当且仅当所有f(v,0)=1时,f(u,1)才是1。

2,d(u,0)的计算:因为u没有选,所以每个子结点v可选可不选,即d(u,0) = sum{max (d(v,0),d(v,1))}。什么情况下方案是唯一的呢?首先,如果某个d(v,0)和d(v,1)相等,则不唯一;其次,如果max取到的那个值对应的f=0,方案也不唯一(如d(v,0)>d(v,1) && f(v,0)==0,则f(u,0)=0;这里可以细分为两种情况)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值