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]);
}

 

posted @ 2016-07-16 10:51  GFY  阅读(267)  评论(0编辑  收藏  举报