트리 DP 예

트리 DP 예

DP는 조금 이상한 느낌이 있지만이 강화되어야하며, 이러한 질문이 너무 일반적입니다


첫째, 주제 링크 : HDU 1520 : 주년 기념 파티


더 클래식 나무 DP 항목의 제목입니다. . . .
DP 배치의 어레이
DP [루트] [0]은 노드가 선택되지 않은 것을 나타낸다
DP [루트] [1]은 노드가 선택되는 것을 나타내고

있다 :

dp[root][0]+=max(dp[son][0],dp[son][1]);
dp[root][1]+=dp[son][0];

세 부분으로 나눌 수 있습니다 것은
A, 성과, 직접 STL의에서 벡터 가 될 수
두, 트리 탐색, DFS
세, DP

#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<iostream>
#include<set>
#include<vector>
#define INF 0x3f3f3f3f
#define ll long long 
using namespace std;
int n;
int dp[6010][5];           //dp[root][1]表示参加宴会,dp[root][0]表示不参加宴会
int value[6010];
int father[6010];
vector<int> tree[6010];
void dfs(int root){
    dp[root][0]=0;
    dp[root][1]=value[root];
    for(int i=0;i<tree[root].size();i++){
        int son=tree[root][i];
        dfs(son);
        dp[root][0]+=max(dp[son][0],dp[son][1]);
        dp[root][1]+=dp[son][0];
    }
}
int main(){
    while(~scanf("%d",&n)){
        for(int i=1;i<=n;i++){
            scanf("%d",&value[i]);
            father[i]=-1;
            tree[i].clear();
        }
        int a,b;
        while(~scanf("%d%d",&a,&b)){
            if(a==0&&b==0)
                break;
            tree[b].push_back(a);
            father[a]=b;
        }
        int root=1;
        //找到根节点
        for(int i=1;i<=n;i++){
            if(father[i]==-1){
                root=i;
            }
        }
        //cout<<root<<endl;
        dfs(root);
        cout<<max(dp[root][1],dp[root][0])<<endl;
    }
    return 0;
}

둘째, 주제 링크 : 루오 구 P1040 플러스 이진 트리


사실, 나는 나무 있지만, 그러나 사실도 DP의 범위를 해결하는 데 사용할 수 있습니다,이 문제가 기분이
정말 기대하지 않았다 시작 심지어 간단한 재귀 예약 주문 탐색 잠시 동안 모든 카드의

#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<iostream>
#include<set>
#include<vector>
#define INF 0x3f3f3f3f
#define ll long long 
using namespace std;
int n;
int flag;             //防止最后一个数后面出现空格           
ll dp[35][35];             //dp数组
int root[35][35];         //存放根节点
ll search(int l,int r){
    ll now;             //存放当前根节点所对应的最大加分值
    if(l>r)
        return 1;
    if(dp[l][r]==-1){
        for(int k=l;k<=r;k++){
            now=search(l,k-1)*search(k+1,r)+dp[k][k];
            if(now>dp[l][r]){
                dp[l][r]=now;
                root[l][r]=k;
            }
        }
    }
    return dp[l][r];
}
void preoder(int l,int r){
    if(l>r)
        return ;
    if(flag==0){
        flag=1;
    }
    else{
        cout<<' ';
    }
    cout<<root[l][r];
    preoder(l,root[l][r]-1);
    preoder(root[l][r]+1,r);
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        for(int j=i;j<=n;j++){
            dp[i][j]=-1;
        }
    }
    for(int i=1;i<=n;i++){
        scanf("%lld",&dp[i][i]);
        root[i][i]=i;
    }
    ll ans=search(1,n);
    printf("%lld\n",ans);
    preoder(1,n);
    cout<<endl;
    return 0;
}
게시 된 127 개 원래 기사 · 원 찬양 32 ·은 10000 +를 볼

추천

출처blog.csdn.net/boliu147258/article/details/103393285