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重载>号时,要从后往前判断
原文地址:https://www.cnblogs.com/newera/p/9080064.html
时间: 2024-10-25 11:02:05