luogu P1272 重建道路
Posted ck666
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu P1272 重建道路相关的知识,希望对你有一定的参考价值。
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个节点的子树的道路的最小数目。
输入输出样例
11 6 1 2 1 3 1 4 1 5 2 6 2 7 2 8 4 9 4 10 4 11
2
说明
【样例解释】
如果道路1-4和1-5被破坏,含有节点(1,2,3,6,7,8)的子树将被分离出来
一开始想了各种神奇的东西,想着是不是要同时考虑上下两部分什么的,后来发现完全可以当成无根树嘛qwq
……↑以上请无视qwq
树形DP一道。没有什么奇奇怪怪的输入真是太好了
f[x][i]记录的是在以第x个点为根的子树上分出i个点的连通块最少需要删掉几条边
初始化f[x][1]当然等于这个点的度数和
dp转移方程f[x][j]=min(f[x][j],f[x][j-k]+f[v][k]-2)
要减2的原因是转移过来的两个连通块之间那条边被删了两次,然而合并后的连通块中这条边不应该被删
具体转移可以看代码qwq
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int N=200; int n,P,p[N],cnt,f[N][N],du[N]; bool vis[N]; struct edge{int to,nex;}e[N<<1]; void add(int u,int v) { e[++cnt]=(edge){v,p[u]}; p[u]=cnt; } void dfs(int x,int fa) { f[x][1]=du[x]; for(int i=p[x];i;i=e[i].nex) { int v=e[i].to; if(v==fa)continue; dfs(v,x); for(int j=P;j>=1;--j) for(int k=1;k<=j;++k) f[x][j]=min(f[x][j],f[x][j-k]+f[v][k]-2); } } int main() { scanf("%d%d",&n,&P); memset(f,0x3f,sizeof(f)); for(int i=1;i<n;++i) { int x,y;scanf("%d%d",&x,&y); add(x,y);add(y,x); ++du[x],++du[y]; } dfs(1,0); int ans=N; for(int i=1;i<=n;++i)ans=min(ans,f[i][P]); cout<<ans<<endl; }
by:wypx
树上dp,随便乱搞就过了,真好玩
把我在luogu上的题解粘过来骗一波访问
把一颗树以1(假装)
为根节点,计算出他有多少个儿子,把他加一就是有多少连出去的边。
重载dfs的w并没有什么用.....
维护一个连通块(dp[i][1]就是把i这个节点删到只剩它自己需要操作多少次),然后大力扩展连通块,通过father节点加点,使其保持p个点在块里。
然后枚举一遍在以没个i所扩展的大小为p的连通块所需要的操作次数
#include<iostream> #include<cstdio> #include<cstdlib> #include<algorithm> #include<queue> #include<cstring> using namespace std; const int maxn=200; const int INT=2333333; int read(){ int an=0,f=1; char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(‘0‘<=ch&&ch<=‘9‘){an=an*10+ch-‘0‘;ch=getchar();} return an*f; } int f[maxn],cnt,fa[maxn],ans=2333; bool vis[maxn]; struct saber{ int to,nex; }b[maxn<<1]; void add(int x,int y){ cnt++; b[cnt].nex=f[x]; b[cnt].to=y; f[x]=cnt; } int son[maxn],dp[maxn][maxn],m,n,p; void dfs(int x){ vis[x]=1;son[x]=1; for(int i=f[x];i;i=b[i].nex){ int v=b[i].to; if(!vis[v]){ dfs(v); fa[v]=x; son[x]++; } } } void dfs(int x,int w){ dp[x][1]=son[x]; for(int i=f[x];i;i=b[i].nex){ int v=b[i].to; if(v!=fa[x]){ dfs(v,w); for(int j=p;j>=1;j--) for(int k=1;k<=j;k++) dp[x][j]=min(dp[x][j],dp[x][j-k]+dp[v][k]-2); } } ans=min(ans,dp[x][p]); } int main(){ n=read();p=read(); for(int i=0;i<=maxn-9;i++) for(int j=0;j<=maxn-9;j++)dp[i][j]=INT; for(int i=1;i<n;i++){ int x,y; x=read();y=read(); add(x,y); add(y,x); } dfs(1);son[1]--; dfs(1,INT); cout<<ans; return 0; }
by:s_a_b_e_r
以上是关于luogu P1272 重建道路的主要内容,如果未能解决你的问题,请参考以下文章