1. 程式人生 > >JZOJ 5455【NOIP2017提高A組衝刺11.6】拆網線

JZOJ 5455【NOIP2017提高A組衝刺11.6】拆網線

目錄:

題目:

傳送門

分析:

f[i][0]表示在x的子樹中,x沒有被選擇的情況下最多有多少對點是兩兩配對的
f[i][1]表示x被選擇的情況
顯然:
f[i][0]=Σf[v][1],f[i][1]=max{f[i][0]f[v][1]+f[v][0]+1}
{vson[i]}
讓後,我們令ans=max{f[1][0],

f[1][1]}
2ans>=m那麼答案就是(m+1)/2
否則就是ans+(m2ans)
顯然沒有兩兩配對的點,可以通過加一條邊來增加一個點(一換一))

程式碼:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>  
#include<cstdlib>
#include<algorithm>
#include<set>
#include<queue>
#include<vector> #include<map> #include<list> #include<ctime> #include<iomanip> #include<string> #include<bitset> #include<deque> #include<set> #define LL long long #define h happy using namespace std; inline LL read() { int d=0,f=1;char s=getchar(); while
(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();} while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();} return d*f; } vector<int> v[100100]; int f[100100][10]; int max(int x,int y){return x>y?x:y;} void dp(int x,int p) { f[x][0]=f[x][1]=0; for(int i=0;i<v[x].size();i++) { int son=v[x][i]; if(son!=p) { dp(son,x); f[x][0]+=f[son][1]; } } for(int i=0;i<v[x].size();i++) { int son=v[x][i]; if(son!=p) f[x][1]=max(f[x][1],f[x][0]-f[son][1]+f[son][0]+1); } return; } int main() { int king=read(); while(king) { v[1].clear(); int n=read(),m=read(),x; for(int i=2;i<=n;i++) { v[i].clear(); x=read(); v[x].push_back(i); } dp(1,0); int ans=max(f[1][0],f[1][1]); if(ans*2>=m) printf("%d\n",(m+1)>>1); else printf("%d\n",ans+(m-ans*2)); king--; } return 0; }