sd省队集训二轮tree

11 篇文章 0 订阅
6 篇文章 0 订阅

这里写图片描述

感觉这题应该跟hdu5290很像,结果它们果然系出同源;
这个题应该处于更根源的位置;

根据算法3的思想,令dp[i][j][k]表示以i为根的子树且已经使用了j个黑点,最深未被覆盖的长度或者沿着根最多能覆盖多少长度。
但是这样状态会很多无法存下。
考虑将k表示成还拥有一个黑点k,使得点i为根的子树全被保护。
令T[i]表示[i不是黑点]
枚举k,当点u枚举到一个儿子v时,通过dp[u][j1][k]+dp[v][j2][k2]来转移到dp[u][j1+j2][k],或者通过dp[u][j1][k]+dp[v][j2][k]-T[k]来转移到dp[u][j1+j2-1][k]。
其中k2是可以不需要枚举的,存储最小值即可。
最终答案存储于dp[root][黑点数量][k]中。

这样hdu5290中的f,g数组就得到了统一,具体再感受下;
from std…

#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <assert.h>
using namespace std;
int o,dis[505][505],n,i,MAX,j,A,B,C,m,chang[10005],next[1005],e[1005],head[1005],fa[1005],T[1050],a[1005],sum,siz[1005],DP[1005],k,ans;
bool v[1005];
short dp[505][505][505],Be[505][505];
void dfs(int x,int y)
{
    dis[x][i]=y;
    int now=head[x];
    while (now!=0)
    {
        if (!v[e[now]])
        {
            v[e[now]]=true;
            dfs(e[now],min(y+chang[now],1000000005));
        }
        now=next[now];
    }
}
void dfs2(int x,int y)
{
    MAX=max(MAX,y);
    int now=head[x]; siz[x]=1;
    while (now!=0)
    {
        if (!v[e[now]])
        {
            v[e[now]]=true;
            fa[e[now]]=x;
            dfs2(e[now],y+1);
        }
        now=next[now];
    }
    for (int j=1; j<=n; j++)
    if (dis[x][j]<=m)
    {
        now=head[x]; siz[x]=1;
        dp[x][j][1]=T[j];
        while (now!=0)
        {
            if (fa[e[now]]==x)
            {
                for (int k=1; k<=siz[x]; k++)
                  for (int l=1; l<=siz[e[now]]; l++)
                  {
                      DP[k+l-1]=min(DP[k+l-1],dp[x][j][k]+dp[e[now]][j][l]-T[j]);
                      DP[k+l]=min(DP[k+l],dp[x][j][k]+Be[e[now]][l]);
                  }
                siz[x]+=siz[e[now]];
                for (int k=1; k<=siz[x]; k++) {dp[x][j][k]=DP[k];DP[k]=1000;}
            }
            now=next[now];
        }
    }
    for (int j=1; j<=n; j++) for (int k=1; k<=siz[x]; k++) Be[x][k]=min(Be[x][k],dp[x][j][k]);
}
void add(int a,int b,int c,int d)
{
    e[a]=c;
    next[a]=head[b];
    head[b]=a;
    chang[a]=d;
}
int f[1005];
int getf(int k) {return f[k]==k?f[k]:f[k]=getf(f[k]);}
int main()
{
    freopen("tree.in","r",stdin);
    freopen("tree.out","w",stdout);
    scanf("%d%d",&n,&m);assert(1<=n && n<=500 && 1<=m && m<=1000000000);
    for (i=1; i<=n; i++)
    {
        scanf("%d",&a[i]); assert(0<=a[i] && a[i]<2);
        if (a[i]) sum++;
    }
    for (i=1; i<=n; i++) f[i]=i;
    for (i=1; i<n; i++)
    {
        scanf("%d%d%d",&A,&B,&C);
        assert(1<=A && A<=n && 1<=B && B<=n && 1<=C && C<=1000000000);
        f[getf(A)]=getf(B);
        add(++o,A,B,C);
        add(++o,B,A,C);
    }
    for (i=2; i<=n; i++) assert(getf(i)==getf(1));
    for (i=1; i<=n; i++)
    {
        for (j=1; j<=n; j++) v[j]=false;
        v[i]=true;
        dfs(i,0);
    }
    for (i=1; i<=n; i++) v[i]=false;
    v[1]=true;
    for (k=0; k<=n; k++) DP[k]=1000;
    for (i=0; i<=n; i++) for (j=0; j<=n; j++) Be[i][j]=1000;
    for (i=0; i<=n; i++)
      for (j=0; j<=n; j++)
        for (k=0; k<=n; k++)
          dp[i][j][k]=1000;
    for (i=1; i<=n; i++) T[i]=1-a[i];
    dfs2(1,1);
    ans=1000;
    for (i=1; i<=sum; i++) ans=min(ans,(int)Be[1][i]);
    if (ans>=1000) cout<<-1; else cout<<ans;
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值