51nod 1378 夹克老爷的愤怒

27 篇文章 0 订阅
12 篇文章 0 订阅

1378 夹克老爷的愤怒
基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题 收藏 关注
夹克老爷逢三抽一之后,由于采用了新师爷的策略,乡民们叫苦不堪,开始组织起来暴力抗租。
夹克老爷很愤怒,他决定派家丁常驻村中进行镇压。
诺德县 有N个村庄,编号0 至 N-1,这些村庄之间用N - 1条道路连接起来。
家丁都是经过系统训练的暴力机器,每名家丁可以被派驻在一个村庄,并镇压当前村庄以及距离该村庄不超过K段道路的村庄。
夹克老爷一贯奉行最小成本最大利润的原则,请问要实现对全部村庄的武力控制,夹克老爷需要派出最少多少名家丁?

Input
第1行:2个数N, K中间用空格分隔(1<= N <= 100000, 0 <= K <= N)。
之后N-1行:每行2个数S, E中间用空格分隔,表示编号为S的村庄同编号为E的村庄之间有道路相连。(0 <= S, E < N)。
Output
输出一个数说明要实现对全部村庄的武力控制,夹克老爷需要派出最少多少名家丁?
Input示例
4 1
0 1
0 2
0 3
Output示例
1

这题目本来很简单硬生生做的我吐血。。。。。
其实思路很简单,看结题报告就行了:
树形DP,贪心思想,从叶子节点向上,能不放就不放,到了k长就放一个。
后序遍历,记录不同子树上传的状态,子树状态记录为该子树可以向上管理的(缺少的用负数)
可能A子树放置的家丁可以把B子树的村庄全部覆盖,这样就可以节约家丁数了。
min_length = min(dp[child])
max_length = max(dp[child])
if(min_length <= -K) {
++result;
dp[cur_idx] = K; //子树需要暴力支援深度达到K了,必须在当前位置放置一个家丁,并向上提供K的暴力输出
} else if(max_length + min_length > 0) {
dp[cur_idx] = max_child - 1; //有一个子树放置的家丁能够把全部其他需要镇压的村庄都覆盖
} else {
dp[cur_idx] = min_child - 1; //继续向上级要求暴力支持
}

最后如果root的状态小于0要额外多放一个。

结果我tm硬生生DP的状态里没有加else卡了我1个多小时,我日啊!!!!!!!!

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstring>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define inf 0x3f3f3f3f
using namespace std;
int n,m;
typedef long long ll;
int ans;
const int N=1e5+6;
int next[N*2],tot=0,vis[N],k,go[N*2],head[N*2],dp[N];
inline void add(int x,int y)
{
    go[++tot]=y;
    next[tot]=head[x];
    head[x]=tot;
}
inline void dfs(int x)
{
    int i=head[x];
    vis[x]=1;
    int minn=inf;
    int maxn=-inf;
    while (~i)
    {
        int v=go[i];
        if (!vis[v])
        {
            dfs(v);
            minn=min(minn,dp[v]);
            maxn=max(maxn,dp[v]);
        }
        i=next[i];
    }
    if (minn==inf){dp[x]=-1;}else
    if (minn<=-k)
{
          ans++;
dp[x]=k;}else
    if (maxn+minn>0)dp[x]=maxn-1;
    else dp[x]=minn-1;
    vis[x]=0;
}

int main()
{
    scanf("%d%d",&n,&k);
    ans=0;
    memset(head,-1,sizeof(head));
    fo(i,1,n-1)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        x++,y++;
        add(x,y);
        add(y,x);
    }
    dfs(1);
        if (dp[1]<0)ans++;
        if (k==0)printf("%d",n);else
        printf("%d",ans);
    return 0;
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值