树形DP

去学习了一下树形DP然后发现自己什么都不会!!!!!!

GGGGGGG。

首先是广为人知的一道

没有上司的舞会

emm没啥可说的,很久以前写的一道题

对于每一个节点有两种状态,选上司或选下属,分别做就好了。

因此

dp[i][0]=sum(max(dp[son][1],dp[son][0]));//显然,你不去,那下属就可以想去就去。

dp[i][1]=sum(dp[son][0])+happy[i];//显然你去了那下属就一定不能去。

#include<bits/stdc++.h>
using namespace std;
vector<int>son[10010];
int f[10010][2],v[10010],h[10010],n;
void dp(int x){
    f[x][0]=0;
    f[x][1]=h[x];
    for(int i=0;i<son[x].size();i++){
      int y=son[x][i];
      dp(y);
      f[x][0]+=max(f[y][0],f[y][1]);
      f[x][1]+=f[y][0];     
    }
}
int main(){
    cin>>n;
    for(int i=1;i<=n;i++)cin>>h[i];
    for(int i=1;i<n;i++){
        int x,y;
        cin>>x>>y;
        v[x]=1;
        son[y].push_back(x);
        }
    int root;
    for(int i=1;i<=n;i++){
        if(!v[i]){
            root=i;
            break;
        }
    }
    dp(root);
    cout<<max(f[root][0],f[root][1])<<endl;
}

 

然后是

最大子树和

#include<bits/stdc++.h>
using namespace std;
const int N=5211314; 
struct node{
    int next,to;
} e[N];
int head[N],cnt,n,dp[N],a[N],ans,val[N];
void add(int u,int v){
    e[++cnt].next=head[u];
    e[cnt].to=v;
    head[u]=cnt; 
} 
void dfs(int u,int fa){
    dp[u]=a[u];
    for(int i=head[u];i;i=e[i].next){
        int v=e[i].to;
        if(v!=fa){
           dfs(v,u);
           dp[u]+=max(0,dp[v]); 
        } 
    } 
    ans=max(ans,dp[u]); 
} 
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]); 
    } 
    for(int i=1;i<n;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        add(u,v),add(v,u); 
    } 
    dfs(1,0);
    printf("%d\n",ans);
    return 0; 
} 

 

  

 

选课

 

#include<bits/stdc++.h>
using namespace std;
const int N=5211314;
int n,m;
struct node{
    int next,to;
} e[N];
int head[N],dp[5041][5041],cnt,a[N],val[N];
void add(int u,int v){
    e[++cnt].next=head[u];
    e[cnt].to=v;
    head[u]=cnt; 
} 
void dfs(int u){
    dp[u][1]=val[u]; 
    for(int i=head[u];i;i=e[i].next){
        int v=e[i].to;
        dfs(v);
        for(int j=m;j>=1;j--){
            for(int k=j-1;k>=1;k--){
                dp[u][j]=max(dp[u][j],dp[u][j-k]+dp[v][k]); 
            } 
        } 
    } 
} 
int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
        scanf("%d%d",&a[i],&val[i]); 
        add(a[i],i); 
    } 
        m++;
    dfs(0);
    printf("%d\n",dp[0][m]); 
    return 0;
} 

 

 

  

 

[USACO12FEB]附近的牛Nearby Cows

换根法好题

#include<bits/stdc++.h>
using namespace std;
struct node{
    int to,next;
}e[210001];
int head[100001],len;
int f[100001][21],sons[100001];//状态,孩子数
int a,b,n,k;
void build(){
    e[++len].to=b;
    e[len].next=head[a];
    head[a]=len;
    e[++len].to=a;
    e[len].next=head[b];
    head[b]=len;
    sons[a]++;sons[b]++;
}
int main(){
    int i,j,s;
    scanf("%d%d",&n,&k);
    for(i=1;i<n;i++){
        scanf("%d%d",&a,&b);
        build();
    }
    for(i=1;i<=n;i++)cin>>f[i][0];
    for(j=1;j<=k;j++)
        for(i=1;i<=n;i++){
            for(s=head[i];s;s=e[s].next)
                f[i][j]+=f[e[s].to][j-1];
            if(j>1)f[i][j]-=(sons[i]-1)*f[i][j-2];
            else f[i][1]+=f[i][0]; 
        }
    for(i=1;i<=n;i++)
        printf("%d\n",f[i][k]); 
    return 0;
}

 

 

 

  

还有一道也是换根法好题。

【POJ3585】Accumulation Degree

我才不会说我被卡了好久好久。。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define zero(x) memset(x,0,sizeof(x))
using namespace std;
const int N=500001;
struct node{
    int next,to;
} e[N*2];
inline int read() {
    int a = 0;
    char ch = getchar();
    while (!(ch >= '0' && ch <= '9')) ch = getchar();
    while (ch >= '0' && ch <= '9') {
        a = a * 10 + (ch - '0');
        ch = getchar();
    }
    return a;
}
bool vis[N];
int n,T;
int head[N],in[N],val[N],cnt,dp[N],d[N];
void add(int u,int v,int z){
    e[++cnt].next=head[u];
    val[cnt]=z; 
    e[cnt].to=v;
    head[u]=cnt; 
} 
void dps(int x){
    vis[x]=1;
    for(int i=head[x];i;i=e[i].next){
        int v=e[i].to;
        if(vis[v])continue;
        dps(v);
        if(in[v]==1){
           d[x]+=val[i]; 
        } 
        else d[x]+=min(d[v],val[i]); 
    } 
} 
void dfs(int x){
    vis[x]=1;
    for(int i=head[x];i;i=e[i].next){
        int v=e[i].to;
        if(vis[v])continue;
        if(in[x]==1)dp[v]=d[v]+val[i];
        else dp[v]=d[v]+min(dp[x]-min(d[v],val[i]),val[i]);
        dfs(v); 
    } 
} 
int main(){
    int t=read();
    while(t--){
        zero(vis),zero(val),zero(dp),zero(d);zero(in); 
        zero(e),zero(head); 
        scanf("%d",&n);cnt=0;
        for(int i=1;i<n;i++){
            int x=read(),y=read(),z=read();
            in[x]++,in[y]++; 
            add(x,y,z),add(y,x,z); 
        } 
        dps(1);memset(vis,0,sizeof(vis));
        dp[1]=d[1];
        dfs(1);int ans=0;
        for(int i=1;i<=n;i++) ans=max(ans,dp[i]);//求最大值
        printf("%d\n",ans);//输出
    } 
} 

暂时完结以后有新的再填吧。

posted @ 2019-10-31 12:00  wilxx  阅读(137)  评论(0编辑  收藏  举报