cf581F 依赖背包+临时数组 好题

Posted zsben991126

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了cf581F 依赖背包+临时数组 好题相关的知识,希望对你有一定的参考价值。

这题得加个临时数组才能做。。

/*
给定一棵树,树节点可以染黑白,要求叶子节点黑白平分
称连接黑白点的边为杂边,求使得杂边最少的染色方 
那么设dp[i][j][0|1]表示i子树中有j个叶子节点,i染黑或白
那么其实是依赖背包,即枚举每个节点的字数v,进行分组即可
给dp初始化0x3f 
边际条件:如果i是叶子节点,那么dp[i][i][0|1]=0; 
*/ 
#include<bits/stdc++.h>
using namespace std;
#define maxn 5005
struct Edge{int to,nxt;}edge[maxn<<1];
int n,k,flag[maxn],num[maxn],root,dp[maxn][maxn][2],tot,head[maxn];
void init(){
    memset(head,-1,sizeof head);
    tot++; 
}
void addedge(int u,int v){
    edge[tot].to=v;edge[tot].nxt=head[u];head[u]=tot++;
}
int dfs1(int u,int pre){
    num[u]=0;
    if(flag[u]==1)return num[u]=1;
    for(int i=head[u];i!=-1;i=edge[i].nxt){
        int v=edge[i].to;
        if(v!=pre)dfs1(v,u),num[u]+=num[v];
    }
    return num[u];
}
void dfs2(int u,int pre){
    if(flag[u]==1){
        dp[u][1][0]=dp[u][0][1]=0;
        return;
    }
    
    for(int i=head[u];i!=-1;i=edge[i].nxt){
        int v=edge[i].to;
        if(v!=pre)dfs2(v,u);
    }
    
    int tmp[maxn][2];//临时数组,tmp[j]表示j个黑点的最小杂边 
    dp[u][0][0]=dp[u][0][1]=0;//这两种情况 
    for(int i=head[u];i!=-1;i=edge[i].nxt){
        int v=edge[i].to;
        if(v==pre)continue;    
        
        memset(tmp,0x3f,sizeof tmp);
        
        for(int j=num[u];j>=0;j--)
            for(int t=num[v];t>=0;t--){
                tmp[j][0]=min(tmp[j][0],dp[u][j-t][0]+min(dp[v][t][0],dp[v][t][1]+1));
                tmp[j][1]=min(tmp[j][1],dp[u][j-t][1]+min(dp[v][t][1],dp[v][t][0]+1));
            }
        
        for(int j=num[u];j>=0;j--)//每次更新完一次tmp数组都要更新到dp里 
            dp[u][j][0]=tmp[j][0],dp[u][j][1]=tmp[j][1];
     }
    
}
int main(){
    cin>>n;
    int u,v;init();
    for(int i=1;i<n;i++){
        cin>>u>>v;
        addedge(u,v);addedge(v,u);
        flag[u]++,flag[v]++;
    }
    if(n==2){
        printf("%d
",n-1);
        return 0;
    }
    
    memset(dp,0x3f,sizeof dp);
    root=1;
    while(flag[root]==1)root++;
    dfs1(root,0);
    k=num[root]/2;
    dfs2(root,0);
    printf("%d
",min(dp[root][k][0],dp[root][k][1]));
} 

 

以上是关于cf581F 依赖背包+临时数组 好题的主要内容,如果未能解决你的问题,请参考以下文章

cf1143E 倍增好题!

[CF837D] Round Subset(滚动数组,01背包)

CF 632E

[M背包] lc474. 一和零(二维费用背包+好题)

hdu 2955 Robberies (01背包好题)

zoj 3524(拓扑排序+多重背包)(好题)