树形dp-hdu-4714-Tree2cycle

题目连接:

http://acm.hdu.edu.cn/showproblem.php?pid=4714

题目意思:

给一棵树,去掉一条边和增加一条边的花费都为1,求最小的花费,使该树变成一个环。

解题思路:

把任意一节点作为树根,dfs.

对于任何分叉超过1的节点,断开与父亲节点的连接,此时父亲节点就少了一个分叉。然后选两个分支作为两端,其它分支断开再连接共花费2,所有都做完后连到根上面.

先把所有的都连到根上面凑成直线,然后连成环。

代码:

 

#include<iostream>

#include<cmath>

#include<cstdio>

#include<cstdlib>

#include<string>

#include<cstring>

#include<algorithm>

#include<vector>

#include<map>

#include<set>

#include<stack>

#include<list>

#include<queue>

#define eps 1e-6

#define INF 0x3fffffff

#define PI acos(-1.0)

#define ll __int64

#define lson l,m,(rt<<1)

#define rson m+1,r,(rt<<1)|1

#pragma comment(linker, "/STACK:1024000000,1024000000")

using namespace std;



#define Maxn 1010000

struct Edge

{

    int v;

    struct Edge *next;

}*head[Maxn<<1],edge[Maxn<<1];



int n,cnt,ans;



void add(int a,int b)

{

    edge[++cnt].v=b,edge[cnt].next=head[a];

    head[a]=&edge[cnt];

}

int dfs(int cur,int pa) //返回分支个数

{

    int res=0;

    struct Edge * p=head[cur];



    while(p)

    {

        if(p->v!=pa)

            res+=dfs(p->v,cur);

        p=p->next;

    }

    if(res>=2) //超过两个分支,将其它分支连过来

    {

        if(cur==1) //树根

            ans+=res-2; //不用练到其它地方

        else

            ans+=res-1; //选两个,其它的边都要断开和重新连接一次

        return 0; //断开了

    }

    else

        return 1; //作为一个单支

}

int main()

{

    int t;



    scanf("%d",&t);

    while(t--)

    {

        scanf("%d",&n);

        cnt=0;

        memset(head,NULL,sizeof(head));

        for(int i=1;i<n;i++)

        {

            int a,b;

            scanf("%d%d",&a,&b);

            add(a,b);

            add(b,a);

        }

        ans=0;

        dfs(1,0);

        printf("%d\n",ans*2+1);

    }

    return 0;

}


 

 

你可能感兴趣的:(tree)