[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重载>号时,要从后往前判断

posted @ 2018-05-23 22:31  NewErA  阅读(228)  评论(0编辑  收藏  举报