洛谷p1272
题意:给出一棵含有n个结点的树,求最少删除几条边可以得到一个大小为p的子树
题解:树形dp。dp[u][siz]为得到一个以u为根结点大小为siz的树最少需要删除的边数,那么最后结果就是dp[u][p]的最小值+(u是否等于整棵树的根,如果不是则需要+1用于砍掉与根的联系,否则不需要+1)
#include
using namespace std;
#define debug(x) cout<<#x<<" is "<
typedef long long ll;
typedef unsigned long long ull;
const int maxn=155;
const int maxn2=2e4+5;
const ll inf=1e15;
int cnt,head[maxn],siz[maxn],dp[maxn][maxn],out[maxn];
struct edge{
int fr;
int to;
int nex;
}e[maxn<<1];
void adde(int x,int y){
e[cnt].fr=x;
e[cnt].to=y;
e[cnt].nex=head[x];
head[x]=cnt++;
}
void dfs(int u,int f){
siz[u]=1;
for(int i=head[u];i!=-1;i=e[i].nex){
int v=e[i].to;
if(v==f)continue;
dfs(v,u);
siz[u]+=siz[v];
}
dp[u][siz[u]]=0;
}
void dfs2(int u,int f){
dp[u][1]=out[u];
for(int i=head[u];i!=-1;i=e[i].nex){
int v=e[i].to;
if(v==f)continue;
dfs2(v,u);
for(int j=siz[u]-1;j>=1;j--){
for(int k=min(j-1,siz[v]);k>=1;k--){
dp[u][j]=min(dp[u][j],dp[u][j-k]+dp[v][k]-1);
/* if(u==1&&j==1&&dp[u][j]==3){
debug(k);
debug(v);
debug(dp[u][j-k]);
debug(dp[v][k]);
}*/
}
}
}
}
int main(){
int n,p;
scanf("%d%d",&n,&p);
memset(head,-1,sizeof(head));
memset(dp,0x3f3f3f3f,sizeof(dp));
for(int i=1;i<n;i++){
int a,b;
scanf("%d%d",&a,&b);
adde(a,b);
adde(b,a);
out[a]++;
}
dfs(1,0);
dfs2(1,0);
int ans=0x3f3f3f3f;
for(int i=1;i<=n;i++){
if(i==1){
ans=min(ans,dp[i][p]);
}
else{
ans=min(ans,dp[i][p]+1);
}
// debug(i);
// debug(dp[i][p]);
}
printf("%d\n",ans);
return 0;
}
洛谷p1273
题意:给出一棵以1为根的含有n个结点的树,树的边权值为非正数,树的叶子结点权值为非负数,其余结点权值为0,求包含根节点1且点权值+边权值为非负数的子树最多包含的叶子结点的个数
题解:树形dp。dp[u][num]为以u为根节点包含num个叶子结点的树的点权值+边权值的最大值,则显然可以推出树与其子树之间的转移方程,最后找到dp[1][num]为非负数的最大num即可
#include
using namespace std;
#define debug(x) cout<<#x<<" is "<
typedef long long ll;
typedef unsigned long long ull;
const int maxn=3e3+5;
const int maxn2=2e4+5;
const ll inf=1e15;
int cnt,head[maxn],num[maxn];
ll val[maxn],dp[maxn][maxn];
struct edge{
int fr;
int to;
int nex;
ll val;
}e[maxn];
void adde(int x,int y,int z){
e[cnt].fr=x;
e[cnt].to=y;
e[cnt].val=z;
e[cnt].nex=head[x];
head[x]=cnt++;
}
void dfs(int u,int f){
int cntt=0;
for(int i=head[u];i!=-1;i=e[i].nex){
int v=e[i].to;
if(v==f)continue;
dfs(v,u);
cntt++;
num[u]+=num[v];
for(int j=num[u];j>=1;j--){
for(int k=min(j,num[v]);k>=1;k--){
dp[u][j]=max(dp[u][j],dp[u][j-k]+dp[v][k]-e[i].val);
}
}
}
if(!cntt){
dp[u][1]=val[u];
num[u]=1;
}
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
memset(head,-1,sizeof(head));
// memset(dp,-1,sizeof(dp));
for(int i=1;i<=n-m;i++){
int k;
scanf("%d",&k);
for(int j=1;j<=k;j++){
int a;
ll b;
scanf("%d%lld",&a,&b);
adde(i,a,b);
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
dp[i][j]=-inf;
}
}
for(int i=n-m+1;i<=n;i++)scanf("%lld",&val[i]);
dfs(1,0);
int ac=0;
for(int i=num[1];i>=0;i--){
// debug(dp[1][i]);
if(dp[1][i]>=0){
ac=i;
break;
}
}
printf("%d\n",ac);
return 0;
}