树形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);
    }
}


posted @ 2014-11-10 17:24  一样菜  阅读(185)  评论(0编辑  收藏  举报