您的位置:首页 > 其它

[2017纪中10-26]摘Galo 树型背包

2017-10-26 16:19 316 查看
题面

裸的树型背包。f[i][j]表示i的子树中选了j个的最优值。

O(n*k^2)+常数优化代码:

#include<iostream>
#include<cstdio>
#define chkmax(a,b) a=max(a,b)
#define ll long long
using namespace std;
const int maxn=100010;
int n,k,w[maxn],sz[maxn];
ll f[10010][1010];
struct edge
{
int t;
edge *next;
}*con[maxn];
void ins(int x,int y)
{
edge *p=new edge;
p->t=y;
p->next=con[x];
con[x]=p;
}
void dp(int v)
{
for(int i=k+1;i>0;i--)
f[v][i]=-1e18;
for(edge *p=con[v];p;p=p->next)
{
dp(p->t);
sz[v]+=sz[p->t];
for(int i=min(sz[v],k+1);i>=0;i--)
for(int j=0;j<=min(i,sz[p->t]);j++)
chkmax(f[v][i],f[v][i-j]+f[p->t][j]);
}
if(con[v]==NULL) sz[v]=1;
chkmax(f[v][1],(ll)w[v]);
}
int main()
{
scanf("%d%d",&n,&k);

4000
for(int i=2;i<=n;i++)
{
int fa;
scanf("%d%d",&fa,&w[i]);
ins(fa,i);
}
dp(1);
ll ans=0;
for(int i=0;i<=k+1;i++)
chkmax(ans,f[1][i]);
printf("%lld",ans);
return 0;
}


O(n*k)DFS序做法:

#include<iostream>
#include<cstdio>
#define chkmax(a,b) a=max(a,b)
#define ll long long
using namespace std;
const int maxn=100010;
int n,k,w[maxn],sz[maxn],tim,dfn[maxn];
ll f[10010][1010];
struct edge
{
int t;
edge *next;
}*con[maxn];
void ins(int x,int y)
{
edge *p=new edge;
p->t=y;
p->next=con[x];
con[x]=p;
}
void dfs(int v)
{
dfn[++tim]=v;
sz[v]=1;
for(edge *p=con[v];p;p=p->next)
{
dfs(p->t);
sz[v]+=sz[p->t];
}
}
int main()
{
scanf("%d%d",&n,&k);k++;
for(int i=2;i<=n;i++)
{
int fa;
scanf("%d%d",&fa,&w[i]);
ins(fa,i);
}
dfs(1);
for(int i=n;i>=1;i--)
for(int j=1;j<=k;j++)
f[dfn[i]][j]=max(f[dfn[i+sz[dfn[i]]]][j-1]+w[dfn[i]],f[dfn[i+1]][j]);
ll ans=0;
for(int i=0;i<=k;i++)
chkmax(ans,f[dfn[1]][i]);
printf("%lld",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: