• P1041 传染病控制 题解


    题目

    题意简述

    在一颗树中的每个深度找出一些不重合的子树,使所有子树的大小之和最大。

    解题思路

    直接暴力dfs(枚举)方案,好像想不到特别有用的剪枝,就打了朴素的搜索,结果就过了(数据范围小)

    先从根节点 dfs 遍历整棵树,把会用到的信息都记录下来(节点的深度,每个节点的子树大小)

    为了后面搜索方案时方便,我还记录了每个深度的点集

    因为子树不能重合,所以又开了一个数组记录当前可以选择作为根节点的点集,每次用上一个深度的可用点拓展出这个深度的可用点

    避免子树重合的方法:不拓展已选节点的子树

    数组变量声明

    v 记录与每个节点有连边的点,sum记录以每个点为根节点的子树大小,deep记录节点深度,k记录每个深度的所有节点,q记录当前每个深度的可用节点。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 310;
    int n, m, a, b, maxn;
    int v[N][N], cntv[N], sum[N], deep[N], k[N][N], cntk[N], q[N][N], cntq[N];
    inline void Go (int p, int fa, int d) {     //遍历整棵树,记录信息 
    	deep[p] = d, sum[p] = 1, k[d][++cntk[d]] = p;
    	for (int i = 1; i <= cntv[p]; i++) 
    	  if (v[p][i] != fa)  Go (v[p][i], p, d + 1), sum[p] += sum[v[p][i]];
    }
    inline void Do (int d, int s, int last) {     //搜索方案 
    	maxn = max (maxn, s);
    	for (int i = 1; i <= cntq[d-1]; i++) 
    	  if (q[d-1][i] != last)   //如果这个点不是上一次选中点,拓展子节点为可用节点 
    	    for (int j = 1; j <= cntv[q[d-1][i]]; j++) 
    		  if (deep[v[q[d-1][i]][j]] == d)  q[d][++cntq[d]] = v[q[d-1][i]][j]; 
    	//if判断避免加入这个点的父节点 
    	for (int i = 1; i <= cntq[d]; i++)
    	   Do (d + 1, s + sum[q[d][i]], q[d][i]), cntq[d+1] = 0;
    }
    int main() {
    	scanf ("%d %d", &n, &m); 
    	for (int i = 1; i <= m; i++) {
    		scanf ("%d %d", &a, &b);
    	    v[a][++cntv[a]] = b, v[b][++cntv[b]] = a;
    	}
    	q[1][1] = 1, cntq[1] = 1;
    	Go (1, 0, 1), Do (2, 0, 0);
    	printf ("%d", n - maxn);
    	return 0;
    }
    

      

  • 相关阅读:
    大学的最后时光---我的毕设日记(二)
    大学的最后时光---我的毕设日记(一)
    记公司同事的一次集体活动
    ssh框架基本原理
    plsql基本操作记录
    eclipse快捷键。
    面向对象的特性:封装继承多态
    设置label中的对齐方式
    pixmap和label设置图片自适应大小
    类的继承
  • 原文地址:https://www.cnblogs.com/whx666/p/11344478.html
Copyright © 2020-2023  润新知