P1272 重建道路(树形dp)
P1272 重建道路
题目描述
一场可怕的地震后,人们用N个牲口棚(1≤N≤150,编号1..N)重建了农夫John的牧场。由于人们没有时间建设多余的道路,所以现在从一个牲口棚到另一个牲口棚的道路是惟一的。因此,牧场运输系统可以被构建成一棵树。John想要知道另一次地震会造成多严重的破坏。有些道路一旦被毁坏,就会使一棵含有P(1≤P≤N)个牲口棚的子树和剩余的牲口棚分离,John想知道这些道路的最小数目。
输入输出格式
输入格式:
第1行:2个整数,N和P
第2..N行:每行2个整数I和J,表示节点I是节点J的父节点。
输出格式:
单独一行,包含一旦被破坏将分离出恰含P个节点的子树的道路的最小数目。
输入输出样例
输入样例#1:
11 6 1 2 1 3 1 4 1 5 2 6 2 7 2 8 4 9 4 10 4 11
输出样例#1:
2
说明
【样例解释】
如果道路1-4和1-5被破坏,含有节点(1,2,3,6,7,8)的子树将被分离出来
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cstring> #define N 151 using namespace std; int n,m,ans,cnt,flag,w; int head[N],son[N],vis[N]; struct node { int u,v,next; }e[N<<1]; inline int read() { int x=0,f=1;char c=getchar(); while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } inline void add(int u,int v) { e[++cnt].v=v;e[cnt].next=head[u];head[u]=cnt; } void dfs2(int u,int tot) { if(son[u]==m) { w=tot; return; } for(int i=head[u];i;i=e[i].next) { int v=e[i].v;if(vis[i])continue; if(son[u]-son[v]>=m) { vis[i]=1; son[u]-=son[v]; tot=tot+1; dfs2(u+1-1,tot); vis[i]=0; } } } void dfs(int u) { if(flag) return; for(int i=head[u];i;i=e[i].next) { dfs(e[i].v); if(son[u]<m) continue; else if(son[u]==m) { printf("1\n"); flag=1;return; } else { int tmp=son[u]; dfs2(u,0); ans=min(ans,w); son[u]=tmp; } } if(flag) return; } void dfs1(int u) { son[u]=1; for(int i=head[u];i;i=e[i].next) { dfs1(e[i].v); son[u]+=son[e[i].v]; } } int main() { int x,y; n=read();m=read(); if(m==1) { printf("1\n"); return 0; } for(int i=1;i<n;i++) { x=read();y=read(); add(x,y); } ans=0x3f3f3f3f;dfs1(1); dfs(1); if(!flag) printf("%d\n",ans); return 0; }
/* 显然树形dp dp[i][j]:i为根断掉子树大小为j最小边数 初始化dp[u][1]=1的度数 转移时枚举当前点断掉多少,算出连到的儿子断掉多少 因为由儿子转移过来,他们之间的连边不能断 但是转移时断掉了两次,所以答案减2 */ #include<iostream> #include<cstdio> #include<cstring> #define N 151 #define inf 0x7f7f7f7f using namespace std; int dp[N][N],head[N],d[N]; int n,m,ans,cnt; struct node { int u,v,next; }e[N<<1]; inline int read() { int x=0,f=1;char c=getchar(); while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } inline void add(int u,int v) { e[++cnt].v=v;e[cnt].next=head[u];head[u]=cnt; } void dfs(int u,int fa) { dp[u][1]=d[u]; for(int i=head[u];i;i=e[i].next) { if(e[i].v!=fa) { dfs(e[i].v,u); for(int j=m;j>=1;j--) for(int k=1;k<=j;k++) dp[u][j]=min(dp[u][j],dp[e[i].v][k]+dp[u][j-k]-2); } }ans=min(ans,dp[u][m]); } int main() { int x,y; memset(dp,1,sizeof dp); n=read();m=read(); for(int i=1;i<n;i++) { x=read();y=read(); add(x,y);add(y,x); d[x]++;d[y]++; } ans=inf; dfs(1,0); printf("%d\n",ans); return 0; }
折花枝,恨花枝,准拟花开人共卮,开时人去时。
怕相思,已相思,轮到相思没处辞,眉间露一丝。