树形DP+贪心(乱搞)(HDU4714)
题意:给出一个树形图,要求把该树形成一个环最少的步骤(断开一条边和形成一条边都需一步)
分析:很明显,要想把树形成一个环,就要先把其分裂成m条子链之后把子链形成环需要的步骤是2*m+1,所以只需要m最小即可;贪心,以度为1的节点为根节点进行深搜,在回溯的时候对于边(u,v)如果son[v]>=2,则需要断开v儿子的son[v]-2条边和<u,v>边,然后删除v节点,依次类推回溯上去最后的结果就是m的值;
#pragma comment(linker, "/STACK:1024000000,1024000000") #include"stdio.h" #include"string.h" #include"stdlib.h" #include"queue" #include"algorithm" #include"string.h" #include"string" #include"math.h" #include"vector" #include"stack" #include"map" #define eps 1e-4 #define inf 10000000 #define M 1001009 #define PI acos(-1.0) using namespace std; struct node { int u,v,next; }edge[M*2]; int t,head[M],vis[M],son[M],degree[M],num,fa[M]; void init() { t=0; memset(head,-1,sizeof(head)); } void add(int u,int v) { edge[t].u=u; edge[t].v=v; edge[t].next=head[u]; head[u]=t++; } void dfs(int u,int f) { for(int i=head[u];~i;i=edge[i].next) { int v=edge[i].v; if(v==f)continue; fa[v]=u; dfs(v,u); if(son[v]>=2) { num+=degree[v]-2;//删除v的n-1个儿子以及<u,v> vis[v]=1;//删除v节点 degree[fa[v]]--;//让其父节点的度-1 } if(!vis[v]) son[u]+=1;//统计儿子个数 } } int main() { int Case,n,i; scanf("%d",&Case); while(Case--) { scanf("%d",&n); init(); memset(degree,0,sizeof(degree)); for(i=1;i<n;i++) { int a,b; scanf("%d%d",&a,&b); add(a,b); add(b,a); degree[a]++; degree[b]++; } num=0; memset(fa,-1,sizeof(fa)); memset(son,0,sizeof(son)); memset(vis,0,sizeof(vis)); int root; for(i=1;i<=n;i++) if(degree[i]==1) { root=i; break; } dfs(root,-1); printf("%d\n",2*num+1); } }