[贪心]JZOJ 3230 【佛山市选2013】树环转换

Description
给定一棵N个节点的树,去掉这棵树的一条边需要消耗值1,为这个图的两个点加上一条边也需要消耗值1。树的节点编号从1开始。在这个问题中,你需要使用最小的消耗值(加边和删边操作)将这棵树转化为环,不允许有重边。

环的定义如下:

(1)该图有N个点,N条边。

(2)每个顶点的度数为2。

(3)任意两点是可达的。

树的定义如下:

(1)该图有N个点,N-1条边。

(2)任意两点是可达的。
 
Input
第一行是一个整数N代表节点的个数。

接下来N-1行每行有两个整数U, V(1 ≤ U, V ≤ N),表示双向边(U, V)
Output
输出把树转化为环的最小消耗值。
 
Sample Input
4
1 2
2 3
2 4
Sample Output
3
 
Data Constraint
对于20%的数据,有1≤N≤10。

对于100%的数据,有1≤N≤1000000。

分析

早上写的时候想的是奇怪的DP

然后搞了一阵子发现可以贪心?

只有一个儿子的节点则保留不变,值上传

两个儿子的节点可以断开与父亲的联系,将子树中所有点连成一条链的代价和断开再连接的代价加入答案

三及以上个儿子的节点可以通过断开若干个儿子的关系转变成两个儿子的状态

这里默认树根是某条链的一端,所以如果树根属于后两种状态时,无需加上断开和连接的代价

最后不要忘了加连接链两端的代价1

 

#include <iostream>
#include <cstdio>
using namespace std;
const int N=1e6+10;
struct Graph {
    int v,nx;
}g[2*N];
int cnt,list[N];
int n,ans;
int f[N];
int stk[N][3],top;
bool b[N];

void Add(int u,int v) {
    g[++cnt]=(Graph){v,list[u]};list[u]=cnt;
    g[++cnt]=(Graph){u,list[v]};list[v]=cnt;
}

void DFS() {
    stk[++top][0]=1;stk[top][1]=0;stk[top][2]=0;
    while (top) {
        int u=stk[top][0];
        if (!list[u]) {
            if (stk[top][2]>=2) ans+=f[u]+(stk[top][1]!=0?2:0);
            b[u]=stk[top][2]<2;
            top--;
            u=stk[top][0];
            if (b[g[list[u]].v]) {
                stk[top][2]++;
                f[u]+=f[g[list[u]].v];
                if (stk[top][2]>2) f[u]+=2;
            }
            list[u]=g[list[u]].nx;
        }
        for (int i=list[u];i;i=list[u]=g[i].nx)
            if (g[i].v!=stk[top][1]) {
                stk[++top][0]=g[i].v,stk[top][1]=u,stk[top][2]=0;
                break;
            }    
    }
}

int main() {
    scanf("%d",&n);
    for (int i=1,u,v;i<n;i++) scanf("%d%d",&u,&v),Add(u,v);
    DFS();
    printf("%d",ans+1);
}
View Code

 

转载于:https://www.cnblogs.com/mastervan/p/11107782.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值