• BZOJ 4033 [HAOI2015]树上染色


    树DP 。 

    考虑每条边对答案的贡献是边两边的黑点数乘积加白点数乘积乘以边长。所以我们只要知道一个点的某个子树中的黑点数就可以算它到子树这条边的贡献。

    就可以树上跑背包。

    注意一是不要随便只开单向边(会GG),二是DP初值设为-1,dp[x][0].dp[x][1]初始为0,这样不会考虑不存在的状态。

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<vector>
    typedef long long LL;
    using namespace std;
    const int maxn=2005;
    int n,k,x,y,z,fir[maxn],nxt
    [maxn*2],to[maxn*2],ecnt,sz[maxn];
    LL val[maxn*2],dp[maxn][maxn];
    void add(int u,int v,LL w) {
        nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v; val[ecnt]=w;
        nxt[++ecnt]=fir[v]; fir[v]=ecnt; to[ecnt]=u; val[ecnt]=w;
    }
    void DFS(int x,int f) {
        sz[x]=1;
        for(int i=fir[x];i;i=nxt[i]) if(to[i]!=f){
            DFS(to[i],x);
            sz[x]+=sz[to[i]];
        }
    }
    void dfs(int x,int f) {
        memset(dp[x],-1,sizeof(dp[x])); dp[x][0]=dp[x][1]=0;
        for(int i=fir[x];i;i=nxt[i]) if(to[i]!=f){
            dfs(to[i],x);
            int u=to[i],up=min(k,sz[x]);
            for(int v=up;v>=0;v--) {
                 for(int j=0;j<=sz[u]&&j<=v;j++) if(dp[x][v-j]!=-1){
                     dp[x][v]=max(dp[x][v],dp[x][v-j]+dp[u][j]+(LL)(j*(k-j)+(sz[u]-j)*(n-sz[u]-k+j))*val[i]);
                 }
            }
        }
    }
    int main()
    {
        //freopen(".in","r",stdin);
        //freopen(".out","w",stdout);
        scanf("%d%d",&n,&k);
        for(int i=1;i<n;i++) {
            scanf("%d%d%lld",&x,&y,&z);
            add(x,y,z);
        }
        DFS(1,0);
        dfs(1,0);
        printf("%lld
    ",dp[1][k]);
        return 0;
    }
    View Code
  • 相关阅读:
    Java三大框架
    单例模式和工厂模式(百度文库)
    使用java代码编辑oracle数据库
    extends 与implements的区别和用法
    介绍MVC编程架构模式
    接口具体是什么东西
    Servlet和JSP的本质和区别
    用户注册,登录,留言系统
    页面跳转的五种方法
    cookie的长度和限制数量
  • 原文地址:https://www.cnblogs.com/Achenchen/p/7524389.html
Copyright © 2020-2023  润新知