算法竞赛入门经典 例题 9-8 树的最大独立集

/*算法竞赛入门经典 例题 9-8 树的最大独立集
 * d[i]表示以i为根的最大独立集的大小
 * 为简便起见  默认输入的第一个节点是根节点 
 * 输入一条边时 第一个顶点是第二个顶点的父节点
 * 节点编号 1...n
 * */
import java.util.Arrays;
import java.util.Scanner;

class Node {
	int num;
	int parent;
	int sumgs;// 孙子节点累加和
	int sums;// 儿子节点累加和

	public Node(int num, int parent) {
		this.num = num;
		this.parent = parent;
	}
}

public class TreeMaxSet {
	static final int MAXN = 100;// 最大节点数
	static Node[] arr = new Node[MAXN];
	static int n;// 实际节点数
	static int m;// 边数
	static int[][] g = new int[MAXN][MAXN];
	static int[] d = new int[MAXN];
	static boolean flag;

	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		while ((n = scanner.nextInt()) > 0) {
			Arrays.fill(d, 0);
			for (int i = 1; i <= n; i++)
				arr[i] = new Node(i, i);
			m = scanner.nextInt();
			for (int i = 0; i < m; i++) {
				int u = scanner.nextInt();
				int v = scanner.nextInt();
				g[u][v] = 1;
				arr[v].parent = u;
			}
			int max = 0, index = 0;
			for (int i = 1; i <= n; i++) {// 对于每个节点更新其父亲和祖父节点的累加值
				int t = dp(i);
				int p = arr[i].parent;// 获得i的父亲节点的num
				int pp = arr[p].parent;// 获得i祖父节点的num
				if (pp == p && p != i) {
					arr[p].sums += t;
				} else if (pp != p) {
					arr[p].sums += t;
					arr[pp].sumgs += t;
				}
				if (arr[p].sums >= arr[pp].sumgs + 1 && arr[p].sums > max) {
					max = arr[p].sums;
					index = p;
					flag = false;
				} else if (arr[pp].sumgs + 1 > arr[p].sums
						&& arr[pp].sumgs + 1 > max) {
					max = arr[pp].sumgs + 1;
					index = pp;
					flag = true;
				}
			}
			System.out.println("the max:" + max);
			if(flag)
				print(index);
			else {
				for(int i=1; i<=n; i++) {
					if(g[index][i] == 1 && arr[i].parent == index)
						print(i);
				}
			}
			System.out.println();
		}
	}

	private static int dp(int i) {
		if (d[i] > 0)
			return d[i];
		d[i] = 1;
		for (int j = 1; j <= n; j++) {
			if (g[i][j] == 1) {// i是j的父亲 找出i的孙子
				for (int k = 1; k <= n; k++) {
					if (arr[k].parent == j)
						d[i] += dp(k);
				}
			}
		}
		return d[i];
	}

	private static void print(int i) {
		System.out.printf("%d ", i);
		for (int j = 1; j <= n; j++) {
			if (g[i][j] == 1 && arr[j].parent == i) {
				for (int k = 1; k <= n; k++) {
					if (arr[k].parent == j)
						print(k);
				}
			}
		}
	}
}
输入:
11
10
1 2   1 3   3 4   3 5   3 6   4 7   4 8   5 9   5 10   6 11
输出:
the max:7
2 3 7 8 9 10 11 




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值