树形DP水题杂记

BZOJ1131: [POI2008]Sta

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

题解:记录每个点的深度,再根据根节点的深度和逐层推导出其他点的深度和。

我用的是BFS

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <queue>
using namespace std;
typedef long long ll;
int n,cnt,ans;
int head[1000010],next[2000010],to[2000010],fa[1000010],s[1000010];
ll f[1000010],g[1000010],siz[1000010];
queue<int> q;
void add(int a,int b)
{
    to[cnt]=b;
    next[cnt]=head[a];
    head[a]=cnt++;
}
int main()
{
    scanf("%d",&n);
    memset(head,-1,sizeof(head));
    int i,a,b,u;
    for(i=1;i<n;i++)
    {
        scanf("%d%d",&a,&b);
        add(a,b);
        add(b,a);
    }
    q.push(1);
    while(!q.empty())
    {
        u=q.front();
        q.pop();
        s[++s[0]]=u;
        siz[u]++;
        for(i=head[u];i!=-1;i=next[i])
        {
            if(to[i]!=fa[u])
            {
                fa[to[i]]=u;
                q.push(to[i]);
            }
        }
    }
    for(i=n;i>=2;i--)
    {
        siz[fa[s[i]]]+=siz[s[i]];
        f[fa[s[i]]]+=siz[s[i]]+f[s[i]];    //f[i]表示i的所有儿子到i的深度之和
    }
    g[1]=f[ans=1];
    for(i=2;i<=n;i++)
    {
        g[s[i]]=g[fa[s[i]]]+n-(siz[s[i]]<<1);    //g[i]表示所有点到i的距离之和,可由g[fa[i]]推出
        if(g[ans]<g[s[i]]||(g[ans]==g[s[i]]&&ans>s[i]))
        ans=s[i];
    }
    printf("%d",ans);
    return 0;
}

POJ3107:Godfather

题意:在树中找一个点,使去掉这个点后,剩余的所有子树节点个数的最大值最小,求满足要求的所有节点。

题解:求出每个子树的节点个数size[x],则答案为min(size[y],n-size[x]),y是x的儿子。

#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
const int maxn=50010;
int n,cnt,minn;
int head[maxn],to[maxn<<1],next[maxn<<1],s[maxn],f[maxn],sta[maxn];
int readin()
{
    int ret=0;    char gc;
    while(gc<‘0‘||gc>‘9‘)    gc=getchar();
    while(gc>=‘0‘&&gc<=‘9‘)    ret=ret*10+gc-‘0‘,gc=getchar();
    return ret;
}
void add(int a,int b)
{
    to[cnt]=b;
    next[cnt]=head[a];
    head[a]=cnt++;
}
void dfs(int x,int fa)
{
    s[x]=1;
    for(int i=head[x];i!=-1;i=next[i])
    {
        if(to[i]!=fa)
        {
            dfs(to[i],x);
            s[x]+=s[to[i]];
            f[x]=max(f[x],s[to[i]]);
        }
    }
    f[x]=max(f[x],n-s[x]);
    minn=min(minn,f[x]);
}
int main()
{
    n=readin();
    memset(head,-1,sizeof(head));
    int i,a,b;
    for(i=1;i<n;i++)
    {
        a=readin(),b=readin();
        add(a,b),add(b,a);
    }
    minn=1<<30;
    dfs(1,0);
    for(i=1;i<=n;i++)    if(f[i]==minn)    sta[++sta[0]]=i;
    for(i=1;i<sta[0];i++)    printf("%d ",sta[i]);
    printf("%d",sta[sta[0]]);
    return 0;
}

POJ1655:Balancing Act

题意:同POJ3107

#include <stdio.h>
#include <iostream>
#include <string.h>
using namespace std;
const int maxn=20010;
int n,minn,ans,cnt;
int s[maxn],to[maxn<<1],next[maxn<<1],head[maxn];
int readin()
{
    int ret=0;    char gc;
    while(gc<‘0‘||gc>‘9‘)    gc=getchar();
    while(gc>=‘0‘&&gc<=‘9‘)    ret=ret*10+gc-‘0‘,gc=getchar();
    return ret;
}
void add(int a,int b)
{
    to[cnt]=b;
    next[cnt]=head[a];
    head[a]=cnt++;
}
void dfs(int x,int fa)
{
    int t=0;
    s[x]=1;
    for(int i=head[x];i!=-1;i=next[i])
    {
        if(to[i]!=fa)
        {
            dfs(to[i],x);
            s[x]+=s[to[i]];
            t=max(t,s[to[i]]);
        }
    }
    t=max(t,n-s[x]);
    if(t<minn||(t==minn&&x<ans))    ans=x,minn=t;
}
void work()
{
    n=readin();
    memset(head,-1,sizeof(head));
    ans=cnt=0,minn=1<<30;
    int i,a,b;
    for(i=1;i<n;i++)
    {
        a=readin(),b=readin();
        add(a,b),add(b,a);
    }
    dfs(1,0);
    printf("%d %d\n",ans,minn);
}
int main()
{
    int t=readin();
    while(t--)    work();
    return 0;
}

BZOJ1827:[Usaco2010 Mar]gather 奶牛大集会

题意:与上一题差不多,只不过不同的点有不同的牛居住,求的是所有牛到核心的最小总路程

题解:见http://www.cnblogs.com/CQzhangyu/p/6178852.html

时间: 2024-12-24 05:31:24

树形DP水题杂记的相关文章

URAL 1039 Anniversary Party 树形DP 水题

1039. Anniversary Party Time limit: 0.5 secondMemory limit: 8 MB Background The president of the Ural State University is going to make an 80'th Anniversary party. The university has a hierarchical structure of employees; that is, the supervisor rela

洛谷P1352 没有上司的舞会(树形DP水题)

题目描述 某大学有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司.现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数Ri,但是呢,如果某个职员的上司来参加舞会了,那么这个职员就无论如何也不肯来参加舞会了.所以,请你编程计算,邀请哪些职员可以使快乐指数最大,求最大的快乐指数. 输入输出格式 输入格式: 第一行一个整数N.(1<=N<=6000) 接下来N行,第i+1行表示i号职员的快乐指数Ri.(-128<=Ri

POJ 2342 &amp;&amp;HDU 1520 Anniversary party 树形DP 水题

一个公司的职员是分级制度的,所有员工刚好是一个树形结构,现在公司要举办一个聚会,邀请部分职员来参加. 要求: 1.为了聚会有趣,若邀请了一个职员,则该职员的直接上级(即父节点)和直接下级(即儿子节点)都不能被邀请 2.每一个员工都有一个兴奋值,在满足1的条件下,要使得邀请来的员工的兴奋值最高 输出最高的兴奋值. 简单的树形DP dp[i][1]:表示以i为根的子树,邀请节点i的最大兴奋值 dp[i][0]:表示以i为根的子树,不邀请节点i的最大兴奋值 先根据入度找出整棵树的根节点, 然后一次DF

树形DP水题系列(1):FAR-FarmCraft [POI2014][luogu P3574]

题目 大意: 边权为1 使遍历树时到每个节点的时间加上点权的最大值最小 求这个最小的最大值 思路: 最优化问题 一眼树形DP 考虑状态设立 先直接以答案为状态 dp[u] 为遍历完以u为根的子树的答案 再考虑状态转移 dp[u]=MAX(dp[to]+1,siz+dp[to]);siz为枚举子树到以to为节点的子树时之前已遍历的总时间 很明显这个转移过来的dp值的最优化依赖于子树遍历的顺序 所以我们需要找到一种最优的子树遍历顺序来使每个子树得到最优的dp值来更新 我们通过观察可以发现 交换任意两

hdu1520Anniversary party 树形dp水题

/* dp[i][0]表示第i个人不去的时候能得到的最大值 dp[i][1]表示第i个人去的时候得到的最大值 状态转移方程: dp[i][0]+=max(dp[next][0],dp[next][1]) dp[i][1]+=dp[next][0] 其中next为其子节点 */ #include<iostream> #include<cstdio> #include<cstring> #include<vector> using namespace std;

POJ 1155 TELE 背包型树形DP 经典题

由电视台,中转站,和用户的电视组成的体系刚好是一棵树 n个节点,编号分别为1~n,1是电视台中心,2~n-m是中转站,n-m+1~n是用户,1为root 现在节点1准备转播一场比赛,已知从一个节点传送数据到达另一个节点,电视台需要一定的费用 若可以传送数据到达用户的节点n-m+1~n,这些用户各自愿意支付一定的费用给电视台 现在电视台希望在不亏本的情况下为尽量多的用户转播比赛 输出最多可以为多少用户转播比赛 背包类型的树形DP第一题 dp[i][j]表示以节点i为根的子树有j个用户获得转播,电视

树形DP经典题

题目传送门 题意: 给出一棵树,求离每个节点最远的点的距离 思路: 把无根树转化成有根树分析, 对于上面那棵树,要求距结点2的最长距离,那么,就需要知道以2为顶点的子树(蓝色圈起的部分,我们叫它Tree(2)),距顶点2的最远距离L1 还有知道2的父节点1为根节点的树Tree(1)-Tree(2)部分(即红色圈起部分),距离结点1的最长距离+dist(1,2) = L2,那么最终距离结点2最远的距离就是max{L1,L2} f[i][0],表示顶点为i的子树的,距顶点i的最长距离 f[i][1]

POJ 3342 树形DP入门题

题目意思和POJ2342一样,只是多加了一个条件,如果最大方案数唯一,输出Yes,不唯一输出No dp的是时候多加一个变量记录答案是否唯一即可 #include "stdio.h" #include "string.h" #include "vector" using namespace std; struct node { int fa; vector<int>child; }data[210]; struct comp { int

POJ 1947 树形DP入门题

给出N个点,N-1个关系,建出树形图,问最少减去几个边能得到节点数为P的树.典型树形DP题 dp[cur][j] :记录cur结点,要得到一棵j个节点的子树去掉的最少边数 转移方程用的背包的思想 对当前树的每一个子树进行计算 砍掉此子树:   dp[cur][j]=dp[cur][j]+1; 不砍掉:           for (l=0;l<=j;l++)  dp[cur][j]=Min(dp[cur][j],dp[cur][l]+dp[next][j-l]); 枚举从该树中留l个节点其他由新