首页 > 其他 > 详细

msc的宠物 二分+树形DP

时间:2020-08-20 09:20:16      阅读:72      评论:0      收藏:0      [点我收藏+]

https://ac.nowcoder.com/acm/contest/7016/E

这题真没想到

考虑一个问题,删除边对极差的影响,-------无论如何删除边都有办法不让让答案变大(可能相等)

利用二分答案,每次算出mid都跑一次dp看看能不能k条边以内完成,dp[x][i]表示以x为根的子树,所有点的数值在list[i] -- list[i] + mid之间最少删除dp[x][i]个边

ans[x]表示ans[x]极差在mid之间最少删除ans[x] t条边

 

具体在代码

 

#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn = 2000+11;
typedef long long ll;
ll inf = 1e15;
ll mid;
ll dp[maxn][maxn];
ll list[maxn];

vector<int>G[maxn];
void add(int x,int y){
    G[x].push_back(y);
}
int n,k;
ll ans[maxn];

int dfs(int x,int fa){ 
	//cout<<x<<endl;
    for(int i = 1;i<=n;i++){
        if(list[x] >= list[i] && list[i] + mid >= list[x]){
            dp[x][i] = 0;
        }
        else{
            dp[x][i] = inf;
        }
    }
    
    for(int i=0;i<G[x].size();i++){
        int p = G[x][i];
        if(p == fa) continue;
        dfs(p,x);

        for(int j=1;j<=n;j++){
            dp[x][j] += min(dp[p][j],ans[p] + 1);
        }
    }
    for(int i = 1;i<=n;i++){
       ans[x] = min(ans[x],dp[x][i]);
    }
    return 0;
}

int jude(){
    for(int i=0;i<=n;i++){
        ans[i] = inf;
    }
    dfs(1,-1);
    return (ans[1] <= k);//可行 
}
int main(){
    
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++){
    	ans[i] = inf;
        scanf("%lld",&list[i]);
    }
    
    for(int i=1;i<n;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y);
        add(y,x);
    }
  	
    ll l = 0;
    ll r = 2e9+7;
    ll cns = 0;
    
    for(int i=0;i<111;i++){
        mid = (l+r)/2;
        if(jude()){//可以,区间加大
            cns = mid;
			r = mid - 1;
        }
        else{
            l = mid + 1;
        }
    }
    
    printf("%lld\n",cns);
    return 0;
}

  

msc的宠物 二分+树形DP

原文:https://www.cnblogs.com/lesning/p/13532766.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!