hdu 4863 Centroid of a Tree 树dp

代码来自baka。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<set>
#include<cmath>
#include<vector>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
const int maxn=200+10;
const int mod=10007;
struct Edge
{
    int v,next;
    Edge(int v=0,int next=0):v(v),next(next){}
}edges[maxn<<1];
int head[maxn],nEdge,n;
void AddEdges(int u,int v)
{
    edges[++nEdge]=Edge(v,head[u]);
    head[u]=nEdge;
    edges[++nEdge]=Edge(u,head[v]);
    head[v]=nEdge;
}
///find centriod
int wval,wroot[2],childs[maxn];
void fcen(int u,int fa)
{
    childs[u]=1;
    int wmax=0;
    for(int k=head[u];k!=-1;k=edges[k].next)
    {
        int v=edges[k].v;
        if(v==fa) continue;
        fcen(v,u);
        childs[u]+=childs[v];
        wmax=max(childs[v],wmax);
    }
    wmax=max(wmax,n-childs[u]);
    if(wmax<wval)
    {
        wval=wmax;
        wroot[0]=u;wroot[1]=-1;
    }
    else if(wmax==wval)
        wroot[1]=u;
}
///cal w[i][j]
int w[maxn][maxn];
void dfs(int u,int fa)
{
    w[u][0]=w[u][1]=1;
    childs[u]=1;
    for(int k=head[u];k!=-1;k=edges[k].next)
    {
        int v=edges[k].v;
        if(v==fa) continue;
        dfs(v,u);
        childs[u]+=childs[v];
    }
    for(int k=head[u];k!=-1;k=edges[k].next)
    {
        int v=edges[k].v;
        if(v==fa) continue;
        for(int i=childs[u];i>=2;--i)
        {
            for(int j=1;j<i&&j<=childs[v];++j)
            {
                w[u][i]+=w[v][j]*w[u][i-j];
                if(w[u][i]>=mod) w[u][i]%=mod;
            }
        }
    }
}
///solve1
int dp[maxn];
int solve1()
{
    dfs(wroot[0],-1);
    int rt=wroot[0];
    int ans=0;
    for(int i=1;i<=n;++i)
        ans=(ans+w[rt][i])%mod;
    for(int k=head[rt];k!=-1;k=edges[k].next)
    {
        for(int i=0;i<=n;++i) dp[i]=w[rt][i];
        int v=edges[k].v;
        for(int i=1;i<=n;++i)
            for(int j=1;j<i;++j)
            {
                dp[i]-=dp[i-j]*w[v][j];
                if(dp[i]<0) dp[i]=(dp[i]%mod+mod)%mod;
            }
        dp[0]=1;
        for(int i=1;i<n;++i)
            dp[i]=(dp[i-1]+dp[i+1])%mod;
        for(int i=1;i<=n;++i)
        {
            ans-=w[v][i]*dp[i-1];
            ans=(ans%mod+mod)%mod;
        }
    }
    return ans;
}
///solve2
int solve2()
{
    dfs(wroot[0],wroot[1]);
    dfs(wroot[1],wroot[0]);
    int ans=0;
    for(int i=1;i<=n;++i)
    {
        ans+=w[wroot[0]][i]*w[wroot[1]][i];
        ans%=mod;
    }
    return ans;
}

void Init()
{
    memset(head,0xff,sizeof(head));
    memset(w,0,sizeof(w));
    nEdge=-1;
    wroot[0]=wroot[1]=-1;
    wval=inf;
}
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int t,tcase=0;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        Init();
        int u,v,ans;
        for(int i=1;i<n;++i)
        {
            scanf("%d%d",&u,&v);
            AddEdges(u,v);
        }
        fcen(1,-1);
        if(wroot[1]==-1) ans=solve1();
        else ans=solve2();
        printf("Case %d: %d\n",++tcase,ans);
    }
    return 0;
}

hdu 4863 Centroid of a Tree 树dp,布布扣,bubuko.com

时间: 2024-08-04 21:11:09

hdu 4863 Centroid of a Tree 树dp的相关文章

HDU 4863 Centroid of a Tree

树的重心,树形$dp$,背包. 树的重心有两个充分必要条件: $1$.某树有两个重心$a$,$b$ $<=>$ $a$与$b$相邻,断开$a$与$b$之间的边之后,两个联通分量内的点的个数相同. $2$.某树有一个重心$a$ $<=>$ 以$a$为根的树,去掉a之后,剩下的联通分量,除去节点个数最多的联通分量后,剩余的联通分量节点个数之和大于等于最大的联通分量的节点个数. 因此,可以先计算出初始树的重心,分两种情况讨论. 如果有两个重心$a$,$b$,那么,我们需要计算出断开$a$

hdu 4912 Paths on the tree(树链剖分+贪心)

题目链接:hdu 4912 Paths on the tree 题目大意:给定一棵树,和若干个通道,要求尽量选出多的通道,并且两两通道不想交. 解题思路:用树链剖分求LCA,然后根据通道两端节点的LCA深度排序,从深度最大优先选,判断两个节点均没被标 记即为可选通道.每次选完通道,将该通道LCA以下点全部标记. #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include

hdu 4912 Paths on the tree(树链拆分+贪婪)

题目链接:hdu 4912 Paths on the tree 题目大意:给定一棵树,和若干个通道.要求尽量选出多的通道,而且两两通道不想交. 解题思路:用树链剖分求LCA,然后依据通道两端节点的LCA深度排序,从深度最大优先选.推断两个节点均没被标 记即为可选通道. 每次选完通道.将该通道LCA下面点所有标记. #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #includ

Codeforces 161 D. Distance in Tree (树dp)

题目链接:http://codeforces.com/problemset/problem/161/D 题意: 给你一棵树,问你有多少对点的距离为k. 思路: dp[i][j]表示离i节点距离为j的点个数,2次dfs,一次从底向上,另一次从顶向下. 1 //#pragma comment(linker, "/STACK:102400000, 102400000") 2 #include <algorithm> 3 #include <iostream> 4 #i

Bestcoder round #65 &amp;&amp; hdu 5593 ZYB&#39;s Tree 树形dp

Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 354    Accepted Submission(s): 100 Problem Description ZYB has a tree with N nodes,now he wants you to solve the numbers of nodes distanced no m

【HDU 5647】DZY Loves Connecting(树DP)

pid=5647">[HDU 5647]DZY Loves Connecting(树DP) DZY Loves Connecting Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others) Total Submission(s): 332    Accepted Submission(s): 112 Problem Description DZY has an unroote

[HDU 6447][YJJ&#39;s Salesman][2018CCPC网络选拔赛 1010][离散化+线段树+DP]

链接: http://acm.hdu.edu.cn/showproblem.php?pid=6447 题意: 左上角(0,0),右下角(10^9,10^9)的网格,其中有n(1<=n<=10^5)个方格内有权值. 一次只能沿右,下,右下三个方向走一个格子,只有沿右下方向走到格子里才可以获得权值. 问从(0,0)到(10^9,10^9)的路径最大权值是多少. 思路: 网格路径权值问题,第一感考虑DP,x从上往下,y从左往右刷表,状态转移方程为dp[i][j]=max(dp[i-1][j],dp[

hdu 3016 Man Down (线段树 + dp)

题目大意: 是男人就下一般层...没什么可以多说的吧. 注意只能垂直下落. 思路分析: 后面求最大值的过程很容易想到是一个dp的过程 . 因为每一个plane 都只能从左边 从右边下两种状态. 然后我们所需要处理的问题就是 ,你如何能快速知道往左边下到哪里,往右边下到哪里. 这就是线段树的预处理. 讲线段按照高度排序. 然后按照高度从小到大加入到树中. 然后去寻找左端点 和 右端点最近覆盖的线段的编号. #include <cstdio> #include <iostream> #

题解 HDU 3698 Let the light guide us Dp + 线段树优化

http://acm.hdu.edu.cn/showproblem.php?pid=3698 Let the light guide us Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 62768/32768 K (Java/Others) Total Submission(s): 759    Accepted Submission(s): 253 Problem Description Plain of despair was