您的位置:首页 > 其它

【cf23E】Tree

2016-07-19 20:59 381 查看
link to problem

【题目大意】

给出一棵树,求一个对树的划分方法使得每棵子树大小的乘积最大。

【题解】树上背包dp

一看到题目的时候想的是贪心(?是可以的然而我太菜了不会?),因为曾经有一道题是拆分序列为2和3的什么什么的。。。= =扯远了

{状态设计} f[i][j] 表示以 i 为根的子树中与 i 的父亲相连的有 j 个节点时,这棵子树的乘积最大值,故最终答案ans=f[1][0];

{转移方程} f[i][j+k]=max(f[i][j]*f[son[i]][k]),其中 j<=size[i], k<=size[son[i]];

【呆马初级版(⊙_⊙)】

#include <cstdio>
#include <cstring>
struct edge{ int to,nxt;}e[2000];
int n,cnt,s[1000],fi[1000],ans,f[705][705];
void add(int u,int v)
{
e[++cnt].to=v;e[cnt].nxt=fi[u];fi[u]=cnt;
}
void dp(int x,int fa)
{
s[x]=1;f[x][1]=1;
for (int i=fi[x];i;i=e[i].nxt)
if (e[i].to!=fa)
{
dp(e[i].to,x);
for (int j=s[x];j>=0;--j)
for (int k=s[e[i].to];k>=0;--k)
f[x][j+k]=max(f[x][j]*f[e[i].to][k],f[x][j+k]);
s[x]+=s[e[i].to];
}
for (int i=1;i<=s[x];++i) f[x][0]=max(f[x][0],f[x][i]*i);
}
int main()
{
scanf("%d\n",&n);
for (int i=1;i<n;++i)
{
int u,v;
scanf("%d%d\n",&u,&v);
add(u,v);add(v,u);
}
dp(1,0);ans=f[1][0];
printf("%d\n",ans);
return 0;
}


【题外话】

真的以为这就结束了吗,其实还要加高精呢(⊙o⊙)!

然后就随便加了个重载然后???炸了???

//当初真的是手贱押位的时候没搞好生生卡一波……



【AC呆马+高精】

#include <cstdio>
#include <cstring>
#define bit 10000
struct edge{ int to,nxt;}e[2000];
struct number{ int a[100];}ans,f[705][705];
int n,cnt,s[1000],fi[1000];
number operator*(number x,number y)
{
number z;
memset(z.a,0,sizeof(z.a));
for (int i=1;i<=x.a[0];++i)
for (int j=1;j<=y.a[0];++j) z.a[i+j-1]+=x.a[i]*y.a[j];
z.a[0]=x.a[0]+y.a[0]-1;
for (int i=1;i<=z.a[0];++i)
{
z.a[i+1]+=z.a[i]/bit;
z.a[i]%=bit;
}
if (z.a[z.a[0]+1]) ++z.a[0];
return z;
}
number max(number x,number y)
{
if (x.a[0]>y.a[0]) return x;
if (x.a[0]<y.a[0]) return y;
for (int i=x.a[0];i;--i)
if (x.a[i]>y.a[i]) return x;
else if (x.a[i]<y.a[i]) return y;
return x;
}
number change(int x){ number a;a.a[0]=1;a.a[1]=x;return a;}
void add(int u,int v)
{
e[++cnt].to=v;e[cnt].nxt=fi[u];fi[u]=cnt;
}
void dp(int x,int fa)
{
s[x]=1;f[x][1].a[0]=f[x][1].a[1]=1;
for (int i=fi[x];i;i=e[i].nxt)
if (e[i].to!=fa)
{
dp(e[i].to,x);
for (int j=s[x];j>=0;--j)
for (int k=s[e[i].to];k>=0;--k)
f[x][j+k]=max(f[x][j]*f[e[i].to][k],f[x][j+k]);
s[x]+=s[e[i].to];
}
f[x][0]=change(s[x]);
for (int i=1;i<=s[x];++i) f[x][0]=max(f[x][0],f[x][i]*change(i));
}
void print(number x)
{
printf("%d",x.a[x.a[0]]);
for (int i=x.a[0]-1;i;--i) printf("%.4d",x.a[i]);
}
int main()
{
scanf("%d\n",&n);
for (int i=1;i<n;++i)
{
int u,v;
scanf("%d%d\n",&u,&v);
add(u,v);add(v,u);
}
dp(1,0);ans=f[1][0];
print(ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  树形dp 高精