题解:P13680 [IAMOI R2] 未送出的花
算半个验题人写写题解。
思路
不难发现父亲的盛开度大于儿子,证明可以考虑交换两个的盛开度,发现只会让所有美丽值不降。
然后就能发现中位数的条件是假的,一朵花的美丽值就是它
于是我们发现,相当于我们每次要求小的与根相连的连通块,满足它们的
考虑 dp。令
初始化
code
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5;
const int M=2e4+5;
int t,n,u,v,cnt,top,a[N],s[N],siz[N],to[M],nxt[M],h[N],f[N][N],g[N];
void save(int u,int v){
to[++cnt]=v;
nxt[cnt]=h[u];
h[u]=cnt;
}
void dfs(int u,int fa){
s[++top]=u;
a[s[(top+1)/2]]++;
for(int i=h[u];i;i=nxt[i]){
if(to[i]==fa) continue;
dfs(to[i],u);
}
top--;
}
void dfs2(int u,int fa){
siz[u]=a[u];
f[u][a[u]]=1;
for(int i=h[u];i;i=nxt[i]){
if(to[i]==fa) continue;
dfs2(to[i],u);
memcpy(g,f[u],sizeof(g));
for(int j=0;j<=siz[u];j++) for(int k=0;k<=siz[to[i]];k++) f[u][j+k]=min(f[u][j+k],g[j]+f[to[i]][k]);
siz[u]+=siz[to[i]];
}
}
void clear(){
for(int i=1;i<=n;i++) a[i]=h[i]=0;
cnt=top=0;
}
int main(){
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i=1;i<n;i++){
scanf("%d%d",&u,&v);
save(u,v);
save(v,u);
}
for(int i=0;i<=n;i++) for(int j=0;j<=n;j++) f[i][j]=1e9;
dfs(1,0);
dfs2(1,0);
for(int i=n-1;i>=1;i--) f[1][i]=min(f[1][i],f[1][i+1]);
for(int i=1;i<=n;i++) printf("%d ",n-f[1][i]+1);
printf("\n");
clear();
}
return 0;
}