• [Codeforces 23E] Tree


    Brief Intro:

    一棵树,删去若干条边,最大化得到的所有连通块大小的乘积

    Algorithm:

    这其实算是一类题型吧,虽然这是我做的第一题

    树形DP,维护关于子树根节点的信息

    此处用dp[i][s],表示以i为根的子树,且i所属连通块的大小为s时的最大值

    转移时还是树形DP的常规套路,用类似背包的形式转移:dp[i的孩子][k]*dp[i][s]  ------->   dp[i][k+s]

    需要注意的是,此题需要高精度,写一个Big Integer模板类即可

    Code:

    #include <bits/stdc++.h>
    
    using namespace std;
    typedef long long ll;
    
    template<class T> inline void putnum(T x)
    {
        if(x<0)putchar('-'),x=-x;
        register short a[20]={},sz=0;
        while(x)a[sz++]=x%10,x/=10;
        if(sz==0)putchar('0');
        for(int i=sz-1;i>=0;i--)putchar('0'+a[i]);
    }
    
    inline ll read()
    {
        char ch;ll num,f=0;
        while(!isdigit(ch=getchar())) f|=(ch=='-');
        num=ch-'0';
        while(isdigit(ch=getchar())) num=num*10+ch-'0';
        return f?-num:num;
    }
    
    const int MAXN=705;
    const int MAXLEN=120;
    
    struct BI  模板类
    {
        int d[MAXLEN],len;
        
        BI(){memset(d,0,sizeof(d)),len=1;}
        BI(int num){*this=num;}
        
        BI& operator = (const int& num)
        {
            memset(d,0,sizeof(d));
            int t=num;len=0;
            while(t) d[++len]=t%10,t/=10;
            return *this;
        }
        
        void clear()
        {
            while(len>1 && !d[len]) len--;
        }
        
        BI operator + (const BI& num)
        {
            BI ret=*this;
            ret.len=max(num.len,len);
            for(int i=1;i<=ret.len;i++)
            {
                ret.d[i]+=num.d[i];
                if(ret.d[i]>=10) ret.d[i]-=10,ret.d[i+1]++; 
            }
            if(ret.d[ret.len+1]) ret.len++;
            return ret;
        }
        
        BI operator * (const BI& num) const
        {
            BI ret;
            for(int i=1;i<=len;i++)
                for(int j=1;j<=num.len;j++)
                    ret.d[i+j-1]+=d[i]*num.d[j];
            for(int i=1;i<=len+num.len;i++)
                ret.d[i+1]+=ret.d[i]/10,ret.d[i]%=10;
            ret.len=len+num.len+1;
            ret.clear();
            return ret;
        }
        
        bool operator > (const BI& num)
        {
            if(num.len!=len) return len>num.len;
            for(int i=len;i>=1;i--)     //注意,比较是从后往前比
                if(d[i]!=num.d[i]) return d[i]>num.d[i];
            return false;
        }
        
        void print()
        {
            for(int i=len;i>=1;i--) putnum(d[i]);
        }
    }dp[MAXN][MAXN];
    
    int n,sz[MAXN];
    vector<int> G[MAXN];
    
    void dfs(int u,int anc)
    {
        sz[u]=1;dp[u][1]=1;
        for(int i=0;i<G[u].size();i++)
        {
            int v=G[u][i];
            if(v==anc) continue;
            dfs(v,u);
            
            for(int Nu=sz[u];Nu>=1;Nu--)
                for(int Nv=sz[v];Nv>=0;Nv--)
                {
                    BI t=dp[u][Nu]*dp[v][Nv];
                    if(t>dp[u][Nu+Nv]) dp[u][Nu+Nv]=t;
                }
            sz[u]+=sz[v];  //size在转移后再更新
        }
        
        for(int i=1;i<=sz[u];i++)
        {
            BI t=dp[u][i]*BI(i);
            if(t>dp[u][0]) dp[u][0]=t;  //用0号存储最值
        }
    }
    
    int main()
    {
        n=read();
        for(int i=1;i<n;i++)
        {
            int x=read(),y=read();
            G[x].push_back(y);G[y].push_back(x);
        }
        dfs(1,0);
        dp[1][0].print();
        return 0;
    }

    Review:

    1、对连续的乘法要敏感,查看是否需要高精度

    2、BI重载>号时,要从后往前判断

  • 相关阅读:
    SVN自动更新测试服务器工作副本(C#写winform程序实现)
    两台服务器上SQL Server数据库数据互操作示例
    ASP.NET根据URL生成网页缩略图示例程序(C#语言)
    Flutter Widget API
    BPM、BPMN、BPMN2.0概念介绍
    H5多图上传调研
    lIUNX如何加载U盘,光盘
    如何解决exchange2003被中继的问题?(网上转载)
    window无法安装服务
    如何在WORD里面插入不同的页眉和页脚
  • 原文地址:https://www.cnblogs.com/newera/p/9080064.html
Copyright © 2020-2023  润新知