树形DP

1. HDU 2196 题目:求出一棵树上的所有点到其他点的最长距离。

思路:取一个根节点进行dfs,先求出每个节点到子节点的最长路和次长路(也就是与最长路不同的最长的路,有可能与最长路长度相等),并记录最长路和次长路通过的相邻节点的标号。然后进行第二次dfs,考虑最长路是通过父节点的情况,如果该节点v在父节点的最长路上,那么需要取次长路,否则就取最长路。

第二次dfs的时候最长路的通过节点还是要更新,因为若某个父节点的最长路是朝祖先走的,那么其子节点的最长路一定朝祖先走,且与v是否在父节点向下的最长路上无关。

#include<iostream>
#include<map>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<queue>
#include<stack>
#include<functional>
#include<set>
#include<cmath>
#define pb push_back
#define fs first
#define se second
#define sq(x) (x)*(x)
#define eps 0.0000000001
using namespace std;
typedef long long ll;
typedef pair<ll,ll> P;
const int maxv=1e4+300;
int N;
vector<P> G[maxv];
int maxd[maxv],maxdn[maxv],smaxd[maxv],smaxdn[maxv];
void dfs1(int u,int f){
    maxd[u]=smaxd[u]=0;
    for(int i=0;i<G[u].size();i++){
        int v=G[u][i].fs;
        int len=G[u][i].se;
        if(v==f) continue;
        dfs1(v,u);
        if(len+maxd[v]>smaxd[u]){
            smaxd[u]=len+maxd[v];
            smaxdn[u]=v;
        }
        if(smaxd[u]>maxd[u]){
            swap(smaxd[u],maxd[u]);
            swap(smaxdn[u],maxdn[u]);
        }
    }
}
void dfs2(int u,int f){
    for(int i=0;i<G[u].size();i++){
        int v=G[u][i].fs;
        int len=G[u][i].se;
        if(v==f) continue;
        if(maxdn[u]==v){
            if(smaxd[u]+len>smaxd[v]){
                smaxd[v]=smaxd[u]+len;
                smaxdn[v]=u;
            }
            if(smaxd[v]>maxd[v]){
                swap(maxd[v],smaxd[v]);
                swap(maxdn[v],smaxdn[v]);
            }
        }else{
            if(maxd[u]+len>smaxd[v]){
                smaxd[v]=maxd[u]+len;
                smaxdn[v]=u;
            }
            if(smaxd[v]>maxd[v]){
                swap(maxd[v],smaxd[v]);
                swap(maxdn[v],smaxdn[v]);
            }
        }
        dfs2(v,u);
    }
}
int main(){
    /////freopen("/home/files/CppFiles/in","r",stdin);
    /*    std::ios::sync_with_stdio(false);
        std::cin.tie(0);*/
    while(cin>>N){
        for(int i=1;i<=N;i++) G[i].clear();
        for(int i=2;i<=N;i++){
            int a,b;
            scanf("%d%d",&a,&b);
            G[i].pb(P(a,b));
            G[a].pb(P(i,b));
        }
        dfs1(1,-1);
        dfs2(1,-1);
        for(int i=1;i<=N;i++){
            printf("%d\n",maxd[i]);
        }
    }
    return 0;
}
View Code

 2. HDU 5290

题目:每个节点有一个爆炸范围,要求用最少的节点炸掉所有节点.

思路:维护up,down两个dp数组,分别表示还能向上炸的,以及下方有部分节点没有炸的最小花费...wa了很久,是因为没有用up[v][0]去更新down,其实这和用up更新up的部分是一样的.

/*
* @author:  Cwind
*/
#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <map>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <queue>
#include <stack>
#include <functional>
#include <set>
#include <cmath>
using namespace std;
#define IOS std::ios::sync_with_stdio (false);std::cin.tie(0)
#define pb push_back
#define PB pop_back
#define bk back()
#define fs first
#define se second
#define sq(x) (x)*(x)
#define eps (1e-10)
#define INF (1000000300)
#define clr(x) memset((x),0,sizeof (x))
#define cp(a,b) memcpy((a),(b),sizeof (b))

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,string> P;


const int maxn=1e5+300;
int n;
int w[maxn];
ll down[maxn][102],up[maxn][102];
vector<int> G[maxn];
void dfs(int v,int f=-1){
    ll sum=0;
    clr(down[v]);
    for(int i=0;i<=100;i++) up[v][i]=n;
    for(int i=0;i<G[v].size();i++){
        int u=G[v][i];
        if(u==f) continue;
        dfs(u,v);
        for(int j=1;j<=100;j++) down[v][j]+=down[u][j-1];
        down[v][0]+=up[u][0];
        if(w[v]>0) sum+=down[u][w[v]-1];
        else sum+=up[u][0];
    }
    for(int i=0;i<G[v].size();i++){
        int u=G[v][i];
        if(u==f) continue;
        up[v][0]=min(up[v][0],up[u][1]+down[v][0]-up[u][0]);
        for(int j=1;j<100;j++)
            if(up[u][j+1]<1e8) up[v][j]=min(up[v][j],up[u][j+1]+down[v][j]-down[u][j-1]);
    }
    up[v][w[v]]=min(up[v][w[v]],sum+1);
    for(int i=99;i>=0;i--) up[v][i]=min(up[v][i],up[v][i+1]);
    down[v][0]=min(down[v][0],up[v][0]);
    for (int i = 1; i <= 100; i++)down[v][i] = min(down[v][i], down[v][i - 1]);
}
int main(){
    freopen("/home/slyfc/CppFiles/in","r",stdin);
    //freopen("/home/slyfc/CppFiles/out","w",stdout);
    while(cin>>n){
        for(int i=0;i<maxn;i++)
        G[i].clear();
        for(int i=1;i<=n;i++)
            scanf("%d",&w[i]);
        for(int i=0;i<n-1;i++){
            int a,b;
            scanf("%d%d",&a,&b);
            G[a].pb(b);G[b].pb(a);
        }
        dfs(1);
        printf("%d\n",(int)up[1][0]);
    }
    return 0;    
}
View Code

 

posted @ 2015-07-29 00:36  PlusSeven  阅读(195)  评论(0编辑  收藏  举报