• 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]));
    } 
  • 相关阅读:
    【spring-boot】spring-boot 事物管理——之注解@Transactional
    【spring-boot】Spring-boot学习-helloWorld
    【Maven】failOnMissingWebXml
    【java基础领域】高内聚、低耦合理解
    Pascal's Triangle
    Remove Nth Node From End of List
    Valid Palindrome
    Longest Common Prefix
    Roman to Integer
    Palindrome Number
  • 原文地址:https://www.cnblogs.com/zsben991126/p/10352117.html
Copyright © 2020-2023  润新知