poj 3689 树形dp

思路: 每个点有三种状态,本身有塔,被子节点的塔覆盖,被父节点的塔覆盖。

#include<map>

#include<set>

#include<cmath>

#include<queue>

#include<cstdio>

#include<vector>

#include<string>

#include<cstdlib>

#include<cstring>

#include<iostream>

#include<algorithm>

#define Maxn 10100

#define Maxm 100010

#define LL __int64

#define Abs(x) ((x)>0?(x):(-x))

#define lson(x) (x<<1)

#define rson(x) (x<<1|1)

#define inf 1000000

#define Mod 1000000007

using namespace std;

int dp[Maxn][3],head[Maxn],vi[Maxn],e;

struct Edge{

    int u,v,val,next;

}edge[Maxn*2];

void init()

{

    memset(dp,0,sizeof(dp));

    memset(head,-1,sizeof(head));

    memset(vi,0,sizeof(vi));

    e=0;

}

void add(int u,int v)

{

    edge[e].u=u,edge[e].v=v,edge[e].next=head[u],head[u]=e++;

    edge[e].u=v,edge[e].v=u,edge[e].next=head[v],head[v]=e++;

}

inline int min(int a,int b,int c)

{

    a=a<b?a:b;

    return a<c?a:c;

}

void dfs(int u)

{

    int i,v;

    vi[u]=1;

    dp[u][0]=1;//有信息塔

    dp[u][1]=0;//由前覆盖

    dp[u][2]=0;//由后覆盖

    int sum=0,f=0,min1=inf;

    for(i=head[u];i!=-1;i=edge[i].next){

        v=edge[i].v;

        if(vi[v]) continue;

        dfs(v);

        dp[u][0]+=min(dp[v][0],dp[v][1],dp[v][2]);

        dp[u][2]+=min(dp[v][1],dp[v][0]);

        if(dp[v][0]<=dp[v][1]){

            sum+=dp[v][0];

            f=1;

        }

        else{

            if(dp[v][0]-dp[v][1]<min1){

                min1=dp[v][0]-dp[v][1];

            }

            sum+=dp[v][1];

        }

    }

    if(f) dp[u][1]=sum;

    else dp[u][1]=sum+min1;

}

int main()

{

    int n,i,j,u,v;

    while(scanf("%d",&n)!=EOF){

        init();

        for(i=1;i<n;i++){

            scanf("%d%d",&u,&v);

            add(u,v);

        }

        dfs(1);

        printf("%d\n",min(dp[1][0],dp[1][1]));

    }

    return 0;

}

 

你可能感兴趣的:(poj)