刚才瞅了半天自己当初写的,终于瞅出来了。。。QWQ
设f[i][j]表示以i为根的子树,包含j个节点所需砍掉的最小边数
那么可知f[u][1]=u的度;
方程:f[u][j]=min(f[u][j],f[u][j-k]+f[v][k]-2);
为何减2? 因为你已经默认了把与自己相连的所有边都去掉了,于是相当于多去了边(u,v)两次,所以要-2
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #define R register int using namespace std; const int Inf=0x3f3f3f3f,N=201; struct edge{ int v,nxt; }e[N<<1]; int n,m,ans=Inf,cnt; int r[N],fir[N],f[N][N]; inline int g() { R ret=0,fix=1; register char ch; while(!isdigit(ch=getchar())) fix=ch=='-'?-1:fix; do ret=(ret<<3)+(ret<<1)+(ch^48); while(isdigit(ch=getchar())); return ret*fix; } inline void add(int u,int v) {e[++cnt].v=v,e[cnt].nxt=fir[u],fir[u]=cnt;} void dfs(int u,int fa) { f[u][1]=r[u]; for(R i=fir[u],v=e[i].v;i;i=e[i].nxt,v=e[i].v) { if(v!=fa) { dfs(v,u); for(R j=m;j>=1;j--) for(R k=1;k<=j;k++) f[u][j]=min(f[u][j],f[u][j-k]+f[v][k]-2); } } ans=min(f[u][m],ans); } signed main() { n=g(),m=g();memset(f,0x3f,sizeof(f)); for(R i=1;i<n;i++) {R u=g(),v=g(); add(u,v),add(v,u); r[u]++,r[v]++;} dfs(1,0); printf("%d\n",ans); }
2019.04.28