现在的位置: 首页 > 综合 > 正文

树形DP

2013年10月11日 ⁄ 综合 ⁄ 共 3085字 ⁄ 字号 评论关闭

HDU 2196 Computer

题意:求树上每一点到其他任意点的最远距离。

题解:树形DP +树的直径的性质。树上一点到树的任意点的最远距离一定是到树的直径的2个端点中的某个点的距离,如若不然,会存在一个比直径更长的路径。因此找到树的一个直径后,答案便迎刃而解。

 

#include <cstdio>
#include <cstring>
#define max(a,b) (a>b?a:b)
const int maxn=10005;
struct Edge {
    int v,next,w;
}edge[maxn*2];
int head[maxn],cnt;
void addedge(int u , int v , int w)
{
    edge[cnt].v=v;
    edge[cnt].w=w;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}
///
int dp[maxn] , dp1[maxn],n;
int *node;
void dfs (int u)
{
    for (int p=head[u] ; ~p ; p=edge[p].next)
    {
        int v=edge[p].v;
        if(~node[v])continue;
        node[v]=node[u]+edge[p].w;
        dfs(v);
    }
}

int main ()
{
    int u,w;
    while (~scanf("%d",&n))
    {
        memset (head , -1 , sizeof(head));
        cnt=0;
        int maxdis=0,maxu=1,maxv=1;
        for (int i=2 ; i<=n ; ++i)
        {
            scanf("%d%d",&u,&w);
            addedge (u , i , w);
            addedge (i , u , w);
        }
        memset (dp , -1 , sizeof(dp));
        memset (dp1 , -1 , sizeof(dp1));

        node=dp;
        dp[1]=0;
        dfs(1);
        for (int i=1 ; i<=n ; ++i)
        {
            if(dp[i]>maxdis)
            {
                maxdis=dp[i];
                maxu=i;
            }
        }
        memset (dp , -1  , sizeof(dp));
        node=dp;
        dp[maxu]=0;
        dfs(maxu);
        maxdis=0;
        for (int i=1 ; i<=n ; ++i)
        {
            if(dp[i]>maxdis)
            {
                maxdis=dp[i];
                maxv=i;
            }
        }
        node=dp1;
        dp1[maxv]=0;
        dfs(maxv);
        for (int i=1 ; i<=n ; ++i)
        {
            printf("%d\n",max(dp[i],dp1[i]));
        }
    }
    return 0;
}

 

 HDU 1520 Anniversary party

 

///4881889 2011-11-02 17:10:07 Accepted 1520 46MS 388K 1514 B C++ Geners 
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int maxn=6005;
int dp[maxn][2];
///第i个点选和不选的最大值;
int node[maxn];
bool son[maxn];

struct Edge {
    int v,next;
}edge[maxn];
int head[maxn], cnt;
void addedge(int u, int v)
{
    edge[cnt].v=v;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}

void dfs (int u)
{
    dp[u][0]=node[u];
    dp[u][1]=0;
    //printf("%d %d\n", u, head[u]);
    for (int p=head[u] ; ~p ; p=edge[p].next)
    {
        const int & v=edge[p].v;
        //printf("u==%d v==%d\n",u, v);
        dfs(v);
        dp[u][0]+=dp[v][1];
        dp[u][1]+=max(dp[v][1], dp[v][0]);
    }
}

int main ()
{
    int n, u, v;
    while (~scanf("%d", &n))
    {
        memset (head, -1, sizeof(head));
        cnt=0;
        memset (son, false, sizeof(son));
        for (int i=0 ; i<n ; ++i)
        {
            scanf("%d", node+i);
        }
        for (int i=0 ; i<n ; ++i)
        {
            scanf("%d%d", &u, &v);
            if((!u) && (!v))break;
            u--,v--;
            addedge(v,u);
            son[u]=true;
        }
        for (int i=0 ; i<n ; ++i)
        {
            if(!son[i])dfs(i);
        }
        int ans=0;
        for (int i=0 ; i<n ; ++i)
        {
            //printf("%d %d\n", dp[i][0], dp[i][1]);
            ans=max(ans, dp[i][0]);
            ans=max(ans, dp[i][1]);
        }

        printf("%d\n", ans);
    }
    return 0;
}

 

POJ 1655 树的重心,求树上一点,以它为根时,它的所有子树的结点最大值最小

 

#include <cstdio>
#include <cstring>
#include <algorithm>
///树的重心,对于拆分树的分治递归算法里,有很好的优化作用
using namespace std;

const int maxn=20000+123;
const int inf=0x3fffffff;

struct Edge {
    int v,next;
}edge[maxn*2];///若存储无向边,边集数组开两倍大小
int head[maxn], cnt;
void addedge(int u, int v)
{
    edge[cnt].v=v;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}

int sum[maxn], max_son[maxn];

void init ()
{
    cnt=0;
    memset (head, -1, sizeof(head));
    memset (sum, 0, sizeof(sum));
    memset (max_son, 0, sizeof(max_son));
}

int n;
void dfs(int u, int past)
{
    sum[u]=1;
    for (int p=head[u] ; ~p ; p=edge[p].next)
    {
        int v=edge[p].v;
        if(v!=past)
        {
            dfs(v, u);
            sum[u]+=sum[v];
            max_son[u]=max(sum[v], max_son[u]);
        }
    }
    max_son[u]=max(max_son[u], n-sum[u]);
}

int center, ans;
void get_bary()
{
    dfs(1, 0);
    ans=inf;
    for (int i=1 ; i<=n ; ++i)
    {
        if(max_son[i]<ans)
        {
            ans=max_son[center=i];
        }
    }
}
int main ()
{
    int cas;
    int u, v;
    scanf("%d", &cas);
    while (cas--)
    {
        init();
        scanf("%d", &n);
        for (int i=1 ; i<n ; ++i)
        {
            scanf("%d%d", &u, &v);
            addedge(u, v);
            addedge(v, u);
        }
        get_bary();
        printf("%d %d\n", center, ans);
    }
    return 0;
}
/*
2
7
2 6
1 2
1 4
4 5
3 7
3 1

12
2 6
1 2
1 4
4 5
3 7
3 2
7 8
9 10
10 11
11 12
6 9

13
2 6
1 6
1 4
6 5
3 7
3 2
7 8
9 10
10 11
11 12
6 9
6 13
*/

 

 

抱歉!评论已关闭.