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;
    }
    
  • 相关阅读:
    MFC之界面提示(CToolTipCtrl类)
    Windows的三种坐标系:屏幕坐标系,非客户区坐标系,客户区坐标系
    【数据库】insert语句
    【js】v-for 的一些用法 :class {{index}}
    jQuery查找选中的checkbox个数
    limit offset
    http状态码
    Whitelabel Error Page
    【Mybatis】Mybatis generator的使用
    【CSS】Bootstrap 图标
  • 原文地址:https://www.cnblogs.com/xyq0220/p/13388064.html
Copyright © 2011-2022 走看看