专栏文章

【2】做题心得 - 2025 NOIP #68 - T3【二分】【动态规划】【树形 DP】

题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@min02wz5
此快照首次捕获于
2025/12/01 18:22
3 个月前
此快照最后确认于
2025/12/01 18:22
3 个月前
查看原文
哦终于开始改这个题了。首先看到最大值最小就考虑一个二分的做法。然后就需要使用树形 DP 来 check 了。状态设计是 fif_i 为以 ii 为根的子树是否有方案合法,如果有就存储父亲边的使用次数。显然可以考虑一个背包转移。然后代码是不困难的。
CPP
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=3e3+10;
int n,dp[N],f[N];
int lmt,res;
vector<int>e[N];
void dfs(int p,int fa){
    if(fa&&e[p].size()==1) 
        return f[p]=1, void(0);
    int S=0;
    for(auto v:e[p])if(v^fa)
        dfs(v,p), S+=f[v];
    dp[0]=1;
    for(int i=1;i<=lmt;i++) dp[i]=0;
    for(auto v:e[p])if(v^fa)
        for(int i=lmt;i>=f[v];i--)
            dp[i]|=dp[i-f[v]];
    f[p]=p!=1;
    for(int i=lmt;i>=0;i--)if(dp[i])
        { f[p]+=S-i; break; }
    if(f[p]>lmt) res=0;
    return;
}
bool check(int x){
    res=1, lmt=x, dfs(1,0);
    return res;
}
void solve(){
    for(int i=1;i<=n;i++)
        e[i].clear(), f[i]=0;
    cin>>n;
    for(int i=1;i<n;i++){
        int u,v;
        cin>>u>>v;
        e[u].push_back(v);
        e[v].push_back(u);
    }
    int l=0,r=n;
    while(l+1<r){
        int mid=(l+r)>>1;
        if(check(mid)) r=mid;
        else l=mid;
    }
    cout<<r<<"\n";
    return;
}
int main(){
    freopen("balance.in","r",stdin);
    freopen("balance.out","w",stdout);
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int T;
    cin>>T;
    while(T--) solve();
    return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...