NOIP模拟(20171023)T3 拆网线

来源:互联网 发布:淘宝汽车配件保证金 编辑:程序博客网 时间:2024/06/10 23:36

求用最小数量的边使得树上至少k个点被这些边覆盖
2kn105
显然,一条边覆盖两个点最好。
考虑最多能有多少边能覆盖两个点,用树形dp即可
复杂度O(n)

#include<bits/stdc++.h>#define LENusing namespace std;inline int getint(){    int x=0,p=1;    char c=getchar();    while(!isdigit(c)){        if(c=='-')p=-1;        c=getchar();    }    while(isdigit(c)){        x=(x<<3)+(x<<1)+(c^'0');        c=getchar();    }    return x*p;}int dp[100005][2];struct tree{    int fa;    vector<int>son;}t[100005];void dfs(int cur){    dp[cur][1]=dp[cur][0]=0;    for(int i=0;i<t[cur].son.size();++i){        int v=t[cur].son[i];        dfs(v);        dp[cur][0]+=max(dp[v][1],dp[v][0]);    }    for(int i=0;i<t[cur].son.size();++i){        int v=t[cur].son[i],x;        if((x=dp[cur][0]-max(dp[v][0],dp[v][1])+dp[v][0]+1)>dp[cur][1]){            dp[cur][1]=x;        }    }}int main(){    int T=getint();    while(T--){        memset(dp,0,sizeof(dp));        memset(t,0,sizeof(t));        int n=getint(),k=getint();        for(int i=2;i<=n;++i){            int fa=getint();            t[fa].son.push_back(i);            t[i].fa=fa;        }        dfs(1);        int ans=max(dp[1][0],dp[1][1]);        //cout<<ans<<endl;        if(k<=ans*2){            cout<<(k+1)/2<<endl;        }        else{            cout<<ans+k-ans*2<<endl;        }    }    return 0;}
原创粉丝点击