[Poi2011]Dynamite

问题:

某个点上的引线被点燃后的1单位时间内,在树上和它相邻的点的引线会被点燃。如果一个有炸 药的点的引信被点燃,那么这个点上的炸 药会爆炸。
求引爆所有炸 药的最短时间。

解:

树形DP+二分答案

设$f1[x]$表示距离x最远的未被点然的炸弹 

    $f2[x]$表示距离x最近的已经被点燃过的炸弹

$f1[x]=max(f1[x],f1[u]) $   u是x的儿子

$f2[x]=min(f2[x],f2[u]) $   u是x的儿子

后序遍历 三种情况

  if(isbo[v]&&f2[v]>t) {
            f1[v]=max(0,f1[v]);             //v是未盖点 取max
        }
    if(f1[v]+f2[v]<=t) {f1[v]=-10000000;}    //能被盖住
    if(f1[v]==t) {num++;f2[v]=0; f1[v]=-10000000;}  //必须要点然
    }

DP即可 注意判断根的情况

code:

#include<stdio.h> 
#include<cstdlib> 
#include<ctime> 
#include<algorithm> 
using namespace std; 
#define maxnn 4000000 
#define inf 100000000 
int isbo[maxnn]; 
int f[maxnn];
int f1[maxnn],f2[maxnn]; 
int n,m; 
int t;
int cnt[maxnn],tr; 
int las[maxnn],nex[maxnn],en[maxnn],le[maxnn],tot; 
 inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
void add(int a,int b) 
{ 
    en[++tot]=b; 
    nex[tot]=las[a]; 
    las[a]=tot; 
} 
void dfs(int fa,int v)
{
    f[v]=fa;
    for(int i=las[v];i;i=nex[i]) 
    { 
        int u=en[i]; 
        if(u!=fa) 
        {
            dfs(v,u);
        }
    }
    cnt[++tr]=v;
 } 
int bfs() 
{     int num=0; 
    for(int y=1;y<=tr;y++)
    {
    int v=cnt[y];
    if(isbo[v]) f1[v]=0; 
    else f1[v]=-100000000; 
    f2[v]=inf; 
    for(int i=las[v];i;i=nex[i]) 
    { 
        int u=en[i]; 
        if(u!=f[v]) 
        { 
            f1[v]=max(f1[v],f1[u]+1); 
            f2[v]=min(f2[v],f2[u]+1); 
        }     
         
    } 
    if(isbo[v]&&f2[v]>t) {
            f1[v]=max(0,f1[v]);
        }
    if(f1[v]+f2[v]<=t) {f1[v]=-10000000;}
    if(f1[v]==t) {num++;f2[v]=0; f1[v]=-10000000;} 
    }
    return num; 
} 
bool ch() 
{ 
    int tot=bfs(); 
    if(f1[1]>=0) tot++;
    return tot<=m; 
} 
int main(){ 
    n=read();m=read();
    int s; 
    int x,y,z; 
    int l=0,r=n-1;
    for(int i=1;i<=n;i++) 
    { 
        isbo[i]=read();
    } 
    for(int i=1;i<n;i++) 
    { 
        x=read();
        y=read(); 
        add(x,y); 
        add(y,x); 
    } 
    dfs(1,1);
    int mid;
    while(l<=r) 
    { 
         mid=(l+r)/2; 
        t=mid;
        if(ch()) r=mid-1; 
        else 
        l=mid+1; 
    } 
    printf("%d",(l));
}

猜你喜欢

转载自www.cnblogs.com/OIEREDSION/p/11370668.html
今日推荐