HDU 4714

HDU 4714

题意:

给出一棵树,设定切断一条边花费跟连接一条边的花费均为1,问将这棵树变为一个圆的最小花费。

钻牛角尖了,钻牛角尖了,一直去抓树的直径,这个时候就体现出队友的重要性了,给了我正确思路,事实上就是将这棵树切成若干棵单支树,要求单支树数量最小,然后再拼起来,就是答案了。

转移状态dp[ i ][ j ],已第I个节点为根的子树的根的可用度数为J的最小单支树数量。每个儿子都可以选择连接父亲与否,推一遍就搞掂了。

因为HDU的编译器原因,用G++,加栈依然会RE,用C++可以AC,所以将DFS改成BFS会更好。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <sstream>
#include <iostream>
#include <algorithm>
#include<cstdlib>
#include<queue>
#pragma comment(linker,"/STACK:1024000000,1024000000")  
using namespace std;

#define N 1000005
#define L(x) x<<1
#define R(x) x<<1|1
#define M(x,y) (x + y)>>1
#define MOD 1000000007
#define MODD 1000000006
#define inf 0x7fffffff
#define llinf 0x7fffffffffffffff
#define LL __int64

struct edge
{
    int v,next;
}e[N + N];

int dp[N][3],cnt;
int visit[N],mark[N],ans;

void addedge(int a,int b)
{
    e[cnt].v = b;
    e[cnt].next = visit[a];
    visit[a] = cnt++;
    e[cnt].v = a;
    e[cnt].next = visit[b];
    visit[b] = cnt++;
}

void dfs(int x)
{
    dp[x][0] = dp[x][1] = dp[x][2] = 1;
    mark[x] = 1;
    for(int i = visit[x];i != -1;i = e[i].next)
    {
        if(mark[e[i].v])
            continue;
        dfs(e[i].v);
        dp[x][0] = min(dp[x][0] + dp[e[i].v][0],dp[x][1] + dp[e[i].v][1] - 1);
        dp[x][1] = min(dp[x][1] + dp[e[i].v][0],dp[x][2] + dp[e[i].v][1] - 1);
        dp[x][2] = dp[x][2] + dp[e[i].v][0];
    }
}

int main()
{
    int i,j,k,l;
    int n,t;
    scanf("%d",&t);
    while(t--)
    {
        memset(visit,-1,sizeof(visit));
        ans = 0;
        scanf("%d",&n);
        for(i = 1,cnt = 0;i < n;i++)
        {
            scanf("%d%d",&j,&k);
            addedge(j,k);
        }
        memset(mark,0,sizeof(mark));
        dfs(1);
        ans = min(min(dp[1][0],dp[1][1]),dp[1][2]);
    //    cout<<ans<<endl;
        printf("%d\n",ans*2 - 1);
    }
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值