ACM-ICPC(10.9) 树形DP

树形DP考点很多,状态转移有时会很复杂,但是也有规律可寻,最重要的是抓住父子关系之间的状态转移。

  • 树的最大独立集:尽量选择多的点,使得任何两个结点均不相邻。​

状态转移,两种方案:

这样用记忆化的方案来做。

另一种,也是很常见的,也是很重要的——刷表法。

计算出一个​ 后,去刷新他的父亲,和祖父结点的值。

  • 树的重心:找到一个点,以这个点为重心,最大子树的结点数最小。

这里需要反选,名字瞎起的,也很常见的哦~,​

  • 树的直径,也可以用树形DP来做,但是两次DFS更常用。

  • 树形背包。

推荐题目:树形DP很具有思维和编程控制能力,题目较多,认真思考。

BZOJ 3722,1131,4753

Description

Fancy爷宣布XJOI群将要选举下一任群主。候选人有两名,分别是XYW和吉丽。共有n个人(从1~n编号)参加这次投票。他们之间形成了一个树结构,根结点(1号结点)为Fancy。树上的结点有两种身份:专家(叶子结点)或领导(非叶子结点)。每位专家都有自己的选择——支持XYW和吉丽之中的一个;每位领导都有若干个下属(儿子结点),领导的选择决定于下属中人数较多的那一方,下属的数目保证为奇数,从而不会出现平局状况。最后,Fancy的选择即为选举结果。吉丽和XYW知道,目前仍有一些专家处于犹豫未决的状态,只要前去游说,就可获得他的支持。但是由于精力不够,每人每天只能选择游说1名专家;XYW起床更早,他比吉丽先进行游说。这样两人交替进行,直到每位专家都有了确定的选择。请问XYW是否有策略保证自己赢得选举胜利?

Input

第一行一个整数n(2<=n<=1000),表示人数。接下来有n行。第i行中,第一个数为ci。如果c[i]<=0,则i是专家,-2表示其支持XYW,-1表示支持吉丽,0表示仍在犹豫;如果c[i]>0,则c[i]为奇数,表示i是领导,其后c[i]个整数为i的下属。(数据保证为树结构,即除了根节点1以外每个结点有且仅有一个上级)

Output

若XYW无法保证胜利,仅输出一行NIE。否则,输出第一行包含TAK和一个非负整数d;输出第二行包含d个整数,按升序排列,表示XYW在必胜策略下,第一天可以选择游说的专家的编号。(如果不存在犹豫不决的专家,且XYW获得胜利的情况下,则d=0,第二行为空行)

Sample Input

43 2 3 4-20-1

Sample Output

TAK 13

HINT

乍一眼看去,很是复杂,树形博弈SG函数,挺麻烦的,但是数据量很小,考虑枚举O(n^2)。

枚举每一个犹豫的人,看是否必胜,统计贡献值即可~

#include <bits/stdc++.h>

using namespace std;

const int maxn = 1005;

struct Edge {
   int to,next;
}e[maxn*2];

int tot;
int n;
int c[maxn];
int head[maxn];

void add(int u,int v) {
   e[++tot].to = v;
   e[tot].next = head[u];
   head[u] = tot;
}

int col[maxn];

int dfs(int u) {
   if(c[u]<=0) return col[u];
   int sum = 0;

   for(int i = head[u]; i ; i = e[i].next) {
       int v = e[i].to;
       sum+=dfs(v);
  }
   if(sum<0) return -1;
   if(sum>0) return 1;
   return 0;
}

int main()
{
   freopen("in.txt","r",stdin);
   scanf("%d",&n);
   for(int i = 1; i <= n; i++) {
       scanf("%d",&c[i]);

       for(int j = 1; j <= c[i]; j++) {
           int v;
           scanf("%d",&v);
           add(i,v);
      }

       if(c[i]==-2)
           col[i] = 1;
       if(c[i]==-1)
           col[i] = -1;
       if(c[i]==0)
           col[i] = 0;
       if(c[i]>0)
           col[i] = 0x3f3f3f3f;
  }

   if(dfs(1)==-1) {
       puts("NIE");
       return 0;
  }

   vector<int> ans;
   for(int i = 1; i <= n; i++) {
       if(col[i]==0) {
           col[i] = 1;
           if(dfs(1)==1) {
               ans.push_back(i);
          }
           col[i] = 0;
      }
  }

   printf("TAK %d\n",ans.size());

   if(ans.size()>0)
       printf("%d",ans[0]);

   for(int i = 1; i < (int)ans.size(); i++)
       printf(" %d",ans[i]);
   puts("");
   return 0;
}

1131

Description

给出一个N个点的树,找出一个点来,以这个点为根的树时,所有点的深度之和最大

Input

给出一个数字N,代表有N个点.N<=1000000 下面N-1条边.

Output

输出你所找到的点,如果具有多个解,请输出编号最小的那个.

Sample Input

81 45 64 56 76 82 43 4

Sample Output

7

抓住父子关系,大部分的树形DP都是自底向上做的,这题例外很少见哦~

​ : 深度之和。

作为儿子结点,可以很容易的转移: ​ 这里就用到反选了哦。

这个DP前提是​ 算对的情况。因此要自顶向上转移。

树形DP,有很多OJ用vector建树会超时,还是习惯用head的向前星形式的哦。

#include <bits/stdc++.h>

using namespace std;

const int maxn = 1e6+5;
typedef long long ll; vector<int> g[maxn];
ll sz[maxn];
int dep[maxn];
ll f[maxn];
int n; /*
void dfs1(int u,int fa,int d) {
   sz[u] = 1;
   dep[u] = d;
   f[u] = dep[u];
   for(int i = 0; i <(int)g[u].size(); i++) {
       int v = g[u][i];
       if(v==fa) continue;
       dfs1(v,u,d+1);
       sz[u] +=sz[v];
       f[u] +=f[v];
   }
} ll minn;
int ret;
void dfs2(int u,int fa) {
   for(int i = 0; i < (int)g[u].size(); i++) {
       int v = g[u][i];
       if(v==fa) continue;
       f[v] = f[u] - sz[v] + n - sz[v];
       dfs2(v,u);
   }
}
*/ struct Edge {
   int to,next;
}e[maxn*2]; int cnt;
int head[maxn];
void add(int u,int v) {
   e[++cnt].to = v;
   e[cnt].next = head[u];
   head[u] = cnt;
} void dfs1(int u,int fa,int d) {
   sz[u] = 1;
   dep[u] = d;
   f[u] = dep[u];
   for(int i = head[u]; i; i=e[i].next) {
       int v = e[i].to;
       if(v==fa) continue;
       dfs1(v,u,d+1);
       sz[u] +=sz[v];
       f[u] +=f[v];
  }
} ll minn;
int ret; void dfs2(int u,int fa) {
   for(int i = head[u]; i; i=e[i].next) {
       int v = e[i].to;
       if(v==fa) continue;
       f[v] = f[u] - sz[v] + n - sz[v];
       dfs2(v,u);
  }
} int read()
{
   int x=0,f=1;char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
   while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
   return x*f;
} int main()
{
   //scanf("%d",&n);
   n = read();
   int u,v;
   for(int i = 1; i < n; i++) {
       u = read();
       v = read();
       add(u,v);
       add(v,u);
  }    dfs1(1,0,0);
   dfs2(1,0);
   minn = -1;
   for(int i = 1; i <= n; i++) {
       if(minn<f[i])
      {
           minn = f[i];
           ret = i;
      }
  }
   printf("%d\n",ret);
   return 0;
}

bzoj 4753

需要用到01分数规划。

先做两个01分数规划的入门题吧~

ACM-ICPC(10 / 9)的更多相关文章

  1. 程序设计入门——C语言 第5周编程练习 1高精度小数(10分)

    1 高精度小数(10分) 题目内容: 由于计算机内部表达方式的限制,浮点运算都有精度问题,为了得到高精度的计算结果,就需要自己设计实现方法. (0,1)之间的任何浮点数都可以表达为两个正整数的商,为了 ...

  2. PTA练习题之7-1 矩阵转置(10 分)

    7-1 矩阵转置(10 分) 将一个3×3矩阵转置(即行和列互换). 输入格式: 在一行中输入9个小于100的整数,其间各以一个空格间隔. 输出格式: 输出3行3列的二维数组,每个数据输出占4列. 输 ...

  3. PTA练习题之6.1统计字符串中大小写字母的个数(10 分)

    统计字符串中大小写字母的个数(10 分) 分别统计字符串中大写字母和小写字母的个数. 函数接口定义: void fun ( char *s, int *a, int *b ); 其中s.a.b 都是用 ...

  4. PTA 最大子列和问题(10 分)

    最大子列和问题(10 分) 给定K个整数组成的序列{ N​1​​, N​2​​, ..., N​K​​ },“连续子列”被定义为{ N​i​​, N​i+1​​, ..., N​j​​ },其中 1≤ ...

  5. test 5.1 高精度小数(10分)

    请写一个程序,输入一个分数,计算出它的小数形式.无论是否可以除尽,输出最多小数点后200位. 题目内容 由于计算机内部表达方式的限制,浮点运算都有精度问题,为了得到高精度的计算结果,就需要自己设计实现 ...

  6. 环状序列(Circular Sequence, ACM/ICPC Seoul 2004, UVa1584)

    长度为n的环状串有n种表示法,分别为从某 个位置开始顺时针得到.例如,图3-4的环状串 有10种表示: CGAGTCAGCT,GAGTCAGCTC,AGTCAGCTCG等. 在这些表示法中,字典序最小 ...

  7. SQL Server安全(10/11):行级别安全(Row-Level Security)

    在保密你的服务器和数据,防备当前复杂的攻击,SQL Server有你需要的一切.但在你能有效使用这些安全功能前,你需要理解你面对的威胁和一些基本的安全概念.这篇文章提供了基础,因此你可以对SQL Se ...

  8. Docker系列教程01-Centos7安装新版Docker教程(10步)

    最近一直忙于开发,没有时间好好总结一下docker的知识.其实现在docker的教程已经很多很多了,但是很多系统的教程都是基于Ubuntu系统,因为官方推荐使用Ubuntu系统啊,原因在于Ubuntu ...

  9. 欢迎来怼——第14次Scrum会议(10/26)

    一.小组信息 队名:欢迎来怼小组成员队长:田继平成员:李圆圆,葛美义,王伟东,姜珊,邵朔,冉华 小组照片 二.开会信息 时间:2017/10/26  17:00~17:13(总计13min).地点:计 ...

随机推荐

  1. 解决windows10活动历史记录删除问题

    Windows10日常办公过程中系统会记录很多活动历史记录信息,我是不希望我的活动历史记录随时可以被别人查看,虽然电脑有设置密码,但是办公电脑还是习惯将历史记录删除掉,并且永远禁用windows10的 ...

  2. GreenPlum 大数据平台--web监控

    一,安装web监控界面 01,准备 下载greenplum cc包,>> 解压缩 02,安装前配置 vim /greenplum/data/master/gpseg-/pg_hba.con ...

  3. Html练习 | 小影志首页练习

    <!DOCTYPE html> <head> <title>小影志首页练习</title> <style> /*应用全页字体*/ .pg-f ...

  4. 创建本地maven仓库

    1.首先从下面地址下载nexus-oss-webapp-2.3.1-01 http://pan.baidu.com/s/1pKOLdbH 2.修改配置文件: 打开:*nexus-oss-webapp- ...

  5. (转)IPC相关的命令

    IPC相关的命令 原文:http://www.cnblogs.com/jjzd/p/6773090.html 进程间通信概述 进程间通信有如下的目的: 1.数据传输,一个进程需要将它的数据发送给另一个 ...

  6. (转)Saltstack系列

    Saltstack系列1:安装配置 Saltstack系列2:Saltstack远程执行命令 Saltstack系列3:Saltstack常用模块及API Saltstack系列4:Saltstack ...

  7. TOJ 3744 Transportation Costs

    描述 Minya Konka decided to go to Fuzhou to participate in the ACM regional contest at their own expen ...

  8. TOJ 2452 Ultra-QuickSort

    描述 In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a se ...

  9. rabbitmq 命令&& rabbitmq教程(一)

    先来个官方教程 http://www.rabbitmq.com 在windows 下 命名 去掉sudo 我是在windows下测试 用net调用 常用命令 控制台命令:sudo rabbitmqct ...

  10. 使用Access作数据库

    import java.sql.*; public class ConnectAccess { public static void main(String args[]){ ConnectAcces ...