Codeforces 23E Tree
http://codeforces.com/problemset/problem/23/E
题意:给一个树,求砍断某些边,使得所有联通块大小的乘积最大。
思路:f[i][j]代表当前把j个贡献给i的父亲(也就是不计入f[i][j])的最大乘积是多少,转移就是背包转移
记得最后统计答案的时候是f[i][j]*j
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<iostream> #define wk sb #define ll long long int tot,son[200005],first[200005],next[200005],go[200005]; int n; struct node{ int a[35],n; }f[705][705]; int read(){ int t=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();} return t*f; } void insert(int x,int y){ tot++; go[tot]=y; next[tot]=first[x]; first[x]=tot; } void add(int x,int y){ insert(x,y);insert(y,x); } node operator *(node a,node b){ node c;c.n=0;for (int i=0;i<=30;i++) c.a[i]=0; c.n=a.n+b.n; for (int i=1;i<=a.n;i++) for (int j=1;j<=b.n;j++){ c.a[i+j-1]+=a.a[i]*b.a[j]; c.a[i+j]+=c.a[i+j-1]/10000; c.a[i+j-1]%=10000; } int j=1; while (j<=c.n||c.a[j]>9999){ c.a[j+1]+=c.a[j]/10000; c.a[j]%=10000; j++; } while (j>1&&c.a[j]==0) j--; c.n=j; return c; } node make(int x){ node c; c.n=0;for (int i=0;i<=30;i++) c.a[i]=0; while (x){ c.a[++c.n]=x%10000; x/=10000; } return c; } node up(node a,node b){ if (a.n>b.n) return a; if (b.n>a.n) return b; for (int i=a.n;i>=1;i--) if (a.a[i]>b.a[i]) return a; else if (b.a[i]>a.a[i]) return b; return a; } void dfs(int x,int fa){ f[x][1]=make(1); son[x]=1; for (int i=first[x];i;i=next[i]){ int pur=go[i]; if (pur==fa) continue; dfs(pur,x); for (int j=son[x];j>=0;j--) for (int k=son[pur];k>=0;k--) f[x][j+k]=up(f[x][j+k],f[x][j]*f[pur][k]); son[x]+=son[pur]; } f[x][0]=make(0); for (int i=1;i<=son[x];i++) f[x][0]=up(f[x][0],f[x][i]*make(i)); } int main(){ n=read(); for (int i=1;i<n;i++){ int x=read(),y=read(); add(x,y); } dfs(1,0); printf("%d",(int)f[1][0].a[f[1][0].n]); for (int i=f[1][0].n-1;i>=1;i--) printf("%.4d",(int)f[1][0].a[i]); }