码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ 2525 [Poi2011]Dynamite 二分+树形贪心

时间:2015-10-03 23:15:57      阅读:361      评论:0      收藏:0      [点我收藏+]

标签:poi   dp   

题意:
n个点,一棵树,有些点是关键点,可以将m个点染色。
求所有关键点到最近的被染色点的距离的最大值最小。
解析:
反正从这道题我是学了一种做题思路?
大爷讲课的时候说的:一般选择某些点的代价相同的话都是贪心,代价不同的话一般都是DP。
想想也挺对的,不过就是没有感悟到过?
反正这题考试的时候我是直接D了贪心的- -!
忘了为啥D了。
显然最大值最小我们需要二分一下这个值。
然后接下来我们从下往上扫整棵树。
节点的状态有几个?
第一种是 子树内没有不被覆盖的关键点,并且子树中有一个节点的贡献可以继续往上。
第二种是 子树内有不被覆盖的关键点,子树中没有节点的贡献可以继续往上。
第三种是 既没有 不被覆盖的关键点,又没有 可以继续往上贡献的点。
第四种是 都有。
但是 我们可以证明,第四种情况存在的话,显然可以在子树外挑一个点来覆盖没有被覆盖的关键点,但是这个时候子树内的挑选的点就没有卵用了,所以这种情况可以归到第三种。
然后具体就是我们贪心讨论的过程了。
贪心的思想就是,能不染就不染
显然第一种我们需要记录还能往上走多少。
第二种我们需要记录最远的不被覆盖的关键点到达目前的根节点的距离

我觉得做法什么的比较次要吧。
还是这句话
一般选择某些点的代价相同的话都是贪心,代价不同的话一般都是DP。
也许这句话能解决我今后贪心和DP的困扰?2333
代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 300100 
using namespace std;
int n,m;
int flag[N];
int head[N];
int status[N];
int document[N];
int cnt;
int tot;
struct node
{
    int from,to,next;
}edge[N<<1];
void init()
{
    memset(head,-1,sizeof(head));
    cnt=1;
}
void edgeadd(int from,int to)
{
    edge[cnt].from=from,edge[cnt].to=to;
    edge[cnt].next=head[from];
    head[from]=cnt++;
}
// 0-> 继续传递
// 1-> 有未被覆盖
// 2-> 既没有传递也没有未被覆盖。 
void dfs(int now,int fa,int dis)
{
    int uncovered=flag[now]-1;
    int near=-1;
    for(int i=head[now];i!=-1;i=edge[i].next)
    {
        int to=edge[i].to;
        if(to==fa)continue;
        dfs(to,now,dis);
    }
    for(int i=head[now];i!=-1;i=edge[i].next)
    {
        int to=edge[i].to;
        if(to==fa)continue;
        if(status[to]==0)
            near=max(near,document[to]-1);
        else if(status[to]==1)uncovered=max(uncovered,document[to]+1); 
    }
    if(near<uncovered)
    {
        if(uncovered==dis)
            document[now]=dis,status[now]=0,tot++;
        else document[now]=uncovered,status[now]=1;
    }else if(near!=-1)document[now]=near,status[now]=0;
    else status[now]=2,document[now]=0;
}
bool check(int dis)
{
    tot=0;
    dfs(1,0,dis);
    if(status[1]==1)tot++;
    return tot<=m?1:0;
} 
int main()
{
    init();
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&flag[i]);
    for(int i=1;i<n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        edgeadd(x,y);
        edgeadd(y,x);
    }
    int l=0,r=n,ans;
    while(l<=r)
    {
        int mid=(l+r)>>1;
        if(check(mid))ans=mid,r=mid-1;
        else l=mid+1;
    }
    printf("%d\n",ans);
} 

版权声明:本文为博主原创文章,未经博主允许不得转载。

BZOJ 2525 [Poi2011]Dynamite 二分+树形贪心

标签:poi   dp   

原文地址:http://blog.csdn.net/wzq_qwq/article/details/48881753

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!