zoukankan      html  css  js  c++  java
  • 2020杭电多校第二场 1007-In Search of Gold 二分+树形dp

    1007-In Search of Gold

    题意

    给你一颗(n)个结点的树,每条边有两种权值(a_i)(b_i),你可以指定其中(k)条边的权值为(a_i),剩余(n-k-1)条边的权值为(b_i),使树的直径最小。

    分析

    二分树的直径(mid),然后树形(dp)来check,状态 (f[i][j]) 为结点 (i) 的子树中有 (j) 条边的权值为 (a_i) 的情况下 (i) 能到达的最远的距离的最小值,在一个结点合并两个儿子的时候判断一下合并完成的最长路径是不是小于等于 (mid) ,小于等于 (mid) 就转移,不然就不转移,最后若(f[root][k])不等于正无穷,就说明整棵子树里存在一种方案,(mid) 就可行,否则不行。注意枚举合并时可以用(j<=min(sz[x],k))来减枝,不然会 (TLE)

    Code

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<iomanip>
    #include<sstream>
    #include<cstdio>
    #include<string>
    #include<vector>
    #include<bitset>
    #include<queue>
    #include<cmath>
    #include<stack>
    #include<set>
    #include<map>
    #define rep(i,x,n) for(int i=x;i<=n;++i)
    #define per(i,n,x) for(int i=n;i>=x;--i)
    #define sz(a) int(a.size())
    #define rson mid+1,r,p<<1|1
    #define pii pair<int,int>
    #define lson l,mid,p<<1
    #define ll long long
    #define pb push_back
    #define mp make_pair
    #define se second
    #define fi first
    using namespace std;
    const double eps=1e-8;
    const int mod=1e9+7;
    const int N=2e4+10;
    const ll inf=1e18;
    int T,n,k;
    struct edg{
    	int x,a,b;
    };
    vector<edg>g[N];
    ll f[N][22];
    int sz[N];
    ll mid;
    ll ans[22];
    void dfs(int u,int fa){
    	sz[u]=1;
    	f[u][0]=0;
    	for(edg it:g[u]){
    		int x=it.x,a=it.a,b=it.b;
    		if(x==fa) continue;
    		dfs(x,u);
    		int now=min(sz[u]+sz[x]+1,k);
    		int up=min(k,sz[x]),up1=min(k,sz[u]);
    		sz[u]+=sz[x];
    		rep(i,0,now) ans[i]=inf;
    		for(int i=0;i<=up1;i++){
    			for(int j=0;j<=up&&i+j<=k;j++){
    				if(f[u][i]+f[x][j]+b<=mid){
    					ans[i+j]=min(ans[i+j],max(f[u][i],f[x][j]+b));
    				}
    				if(i+j+1<=k&&f[u][i]+f[x][j]+a<=mid){
    					ans[i+j+1]=min(ans[i+j+1],max(f[u][i],f[x][j]+a));
    				}
    			}
    		}
    		rep(i,0,now) f[u][i]=ans[i];
    	}
    }
    int main(){
    	//ios::sync_with_stdio(false);
    	//freopen("in","r",stdin);
    	scanf("%d",&T);
    	while(T--){
    		scanf("%d%d",&n,&k);
    		ll l=1,r=0;
    		rep(i,1,n-1){
    			int u,v,a,b;
    			scanf("%d%d%d%d",&u,&v,&a,&b);
    			g[u].pb(edg{v,a,b});
    			g[v].pb(edg{u,a,b});
    			r+=max(a,b);
    		}
    		while(l<=r){
    			mid=l+r>>1;
    			rep(i,1,n) rep(j,0,k) f[i][j]=inf;
    			dfs(1,0);
    			if(f[1][k]!=inf) r=mid-1;
    			else l=mid+1;
    		}
    		printf("%lld
    ",l);
    		rep(i,1,n) g[i].clear();
    	}
    	return 0;
    }
    
  • 相关阅读:
    websocket
    关于Java中的常量优化机制
    关于使用键盘录入Scanner录入不对应类型的错误
    哈希表
    集合-----双列
    树形结构
    leetcode_14: 最长公共前缀
    leetcode_283_移动零
    leetcode_4_ 寻找两个正序数组的中位数
    leetcode_402_ 移掉K位数字
  • 原文地址:https://www.cnblogs.com/xyq0220/p/13388064.html
Copyright © 2011-2022 走看看