8.26
本来以为来高中可以打模拟赛了
结果是自习,这里又不如家里舒服
观察一下感觉有点压抑,只好沉浸自己的世界了
\(target\)
本来这里放了三道新蓝的,结果发现太难了,扔到做题计划里了
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补出来了
那天感觉今天有点烂尾,就没发出来
但是毕竟这个博客只是写给我自己看而已,记录一下刷题
那又有什么好顾虑的呢?

浙公网安备 33010602011771号