8.26

本来以为来高中可以打模拟赛了

结果是自习,这里又不如家里舒服

观察一下感觉有点压抑,只好沉浸自己的世界了

\(target\)

本来这里放了三道新蓝的,结果发现太难了,扔到做题计划里了

P1272

P1272

简化题意,问一棵树中至少删去几条边才能使某一棵子树的大小恰好为 \(p\)

数据范围小,考虑树形dp

设计状态 \(dp[i][j]\) 表示在第 \(i\) 个节点的子树中,保留 \(j\) 个节点至少要删去的边数

对于 \(i\) 的每一棵子树,若舍弃,则应把连接该节点的子树的边割去,否则枚举子树留几个,进行类似背包的转移

CODE
#include<bits/stdc++.h>
#define usetime() (double)clock () / CLOCKS_PER_SEC * 1000.0
using namespace std;
typedef long long LL;
const int maxn=305;
void read(int& x){
	char c;
	bool f=0;
	while((c=getchar())<48) f|=(c==45);
	x=c-48;
	while((c=getchar())>47) x=(x<<3)+(x<<1)+c-48;
	x=(f ? -x : x);
	return;
}
int head[maxn],nxt[maxn],e[maxn];
int n,m;
int mp_cnt;
void init_mp(){
	memset(head,-1,sizeof(head));
	mp_cnt=-1;
}
void add_edge(int u,int v){
	e[++mp_cnt]=v;
	nxt[mp_cnt]=head[u];
	head[u]=mp_cnt;
}
int dp[maxn][maxn];//在节点 u ,获得大小为 s 的子树所需要删除的边的个数
int s[maxn];
int ans=2e9+1;
void dfs(int u){
	s[u]=1;
	dp[u][1]=0;
	for(int i=head[u];~i;i=nxt[i]){
		int v=e[i];
		dfs(v);
		s[u]+=s[v];
		for(int i=s[u];i>=0;i--){
			++dp[u][i];
			for(int j=0;j<=min(s[v],i-1);j++){
				dp[u][i]=min(dp[u][i],dp[u][i-j]+dp[v][j]);
			}
		}
	}
	if(s[u]>=m) ans=min(ans,dp[u][m]+(u!=1));
}
int main(){
	read(n),read(m);
	int u,v;
	init_mp();
	for(int i=1;i<n;i++){
		read(u),read(v);
		add_edge(u,v);
	}
	memset(dp,0x3f,sizeof(dp));
	dfs(1);
	printf("%d",ans);
	return 0;
}
//^o^

\(update \, on \, 8.27\)

昨天晚上还把abc420-f补出来了

那天感觉今天有点烂尾,就没发出来

但是毕竟这个博客只是写给我自己看而已,记录一下刷题

那又有什么好顾虑的呢?

posted @ 2025-08-27 23:06  huangems  阅读(12)  评论(0)    收藏  举报