POJ 3140 Contestants Division (删边,简单树形DP)

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情

应该说删点类型的题目比较直观,因为dfs的时候都是从点考虑的多。

这题是要删一条边使得剩余的两个分支 价值差最小。

也是做的第一题删边,一开始没底,但是仔细观察一下还是比较简单的。

发现可以这样理解:删一个点和它父亲之间的这条边(因为父亲只有一个)。想到这里(这也不难想)就好办了,只要想办法记录每个节点 从它子树和父亲各能收获多少价值,它们的差值便是删除它和它父亲这条边的结果

最后遍历一遍比较出最小差值就可以了。

具体第一遍dfs,记录子树有多少节点

第二遍dfs,能从父亲转移多少节点,(这里稍微注意一下 = 父亲的父亲+ 父亲的其它孩子)


【代码】

/* ***********************************************
Author        :angon

************************************************ */
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <stack>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <stdlib.h>
#include <time.h>
using namespace std;
#define showtime fprintf(stderr,"time = %.15f\n",clock() / (double)CLOCKS_PER_SEC)
#define lld %I64d
#define REP(i,k,n) for(int i=k;i<n;i++)
#define REPP(i,k,n) for(int i=k;i<=n;i++)
#define scan(d) scanf("%d",&d)
#define scanl(d) scanf("%I64d",&d)
#define scann(n,m) scanf("%d%d",&n,&m)
#define scannl(n,m) scanf("%I64d%I64d",&n,&m)
#define mst(a,k)  memset(a,k,sizeof(a))
#define LL __int64
#define N 100005
#define mod 1000000007
#define Rabs(a)  ((a)<0?-(a):(a))
#define min(a,b) (a)<(b)?(a):(b)
inline int read(){int s=0;char ch=getchar();for(; ch<'0'||ch>'9'; ch=getchar());for(; ch>='0'&&ch<='9'; ch=getchar())s=s*10+ch-'0';return s;}

struct Edge
{
    int v,next;
}edge[N*2];
int head[N],tot;
void addedge(int u,int v)
{
    edge[tot].v=v; edge[tot].next=head[u]; head[u]=tot++;
}
LL val[N],dp1[N],dp2[N];

void dfs1(int u,int fa)
{
    dp1[u] = val[u];
    for(int i=head[u]; ~i; i=edge[i].next)
    {
        int v = edge[i].v;
        if(v==fa) continue;
        dfs1(v,u);
        dp1[u] += dp1[v];
    }
}

void dfs2(int u,int fa)
{
    for(int i=head[u]; ~i; i=edge[i].next)
    {
        int v = edge[i].v;
        if(v==fa) continue;
        dp2[v] += dp2[u];
        dp2[v] += dp1[u] - dp1[v];
        dfs2(v,u);
    }
}
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int n,m,cas=1;
    while(~scann(n,m) && (n||m))
    {
        REPP(i,1,n) scanl(val[i]);
        mst(head,-1); tot=0;
        REP(i,0,m)
        {
            int u,v; scann(u,v);
            addedge(u,v);
            addedge(v,u);
        }
        mst(dp2,0);
        dfs1(1,-1);
        dfs2(1,-1);
        LL minc = 1e15;
        for(int i=1;i<=n;i++)
            minc = min(minc, Rabs(dp1[i] - dp2[i]));
        printf("Case %d: %I64d\n",cas++,minc);
    }


    return 0;
}


【另】


A完之后看了下题解发现有更巧妙的办法,只需第一遍dfs,然后比较每个节点

ans = min(ans,abs((2 * dp[u] - sum)));  

sum - 2倍的子树总节点,即删点该节点上面那条边后两个分支的差值。







poj3140——树形搜索 题目大意:每个节点有一个权值,可从任一一分为二,求权和之差的最小值 附:题目链接 建过程和上一道题一样,同时求出每个节点管辖子的规模size,然后在dfs函数中判断:把当前点及其以下从上割开时,者之差是否更小,ans初始值设为所有点权和即可。 出现问题: 1.runtime error,vector&lt;int&gt;设为全局变量然后忘记了每次都要加上clear()... 阅读详情

相关推荐

poj 3140(树形dp)

题目链接:http://poj.org/problem?id=3140 思路:简单树形dp题,dp[u]表示以u为根的子的人数和。 1 #include&lt;iostream&gt; 2 #include&lt;cstdio&gt; 3 #include&lt;cstring&gt; 4 #include&lt;cstdlib&gt; 5 #include&lt;...

weixin_33994444的博客 157

POJ 3140 Contestants Division(简单树形dp)

题意很简单,也比较好读懂。就是求出

I am a slow walker, but I never walk backwards! 931

[poj 3140] Contestants Division  树形DP

Contestants Division Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 9160 Accepted: 2630DescriptionIn the new ACM-ICPC Regional Contest, a special monitoring and submitting system

ATOD 1631

【解题报告】HDU 4679 Terrorist’s destroy -- 树形dp 直径

/* HDU 4679 Terrorist’s destroy 给一棵,任意一条分成了个部分(a,b),求min( max(a.直径,b.直径) * v.w ) 最大直径乘以权 积的最小值 解法: 先找出整棵的直径所在,即个端点ds de 然后保存每个点到ds和de之间的距离 dds[] dde[] 然后从ds(de)开始搜 每个点保存子中到de(ds)

生命有一种绝对 1402

POJ 3140Contestants Divisiondp

POJ 3140Contestants Divisiondp) Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 9121   Accepted: 2623 Description In the new ACM-ICPC Regional Contest, a

ACMer' 1597

POJ 3140 Contestants Division

题目大意: 给出一棵,求去掉一条之后棵子节点权值和作差的最小值。 解题思路: 这不知道怎么用树形DP做,只是个DFS就过了。还手残了一次。思路具体看代码。 下面是代码: #include #include #include #include #include #include #include #include #include #inc

脑残的孩子只有慢慢学。。 4407

POJ 3140——Contestants Division树形DP & & 点权 & 重心变形】

题目传送门 Description In the new ACM-ICPC Regional Contest, a special monitoring and submitting system will be set up, and students will be able to compete at their own universities. However there’s one ...

NIRVANA REBIRTH 369

poj 3140 Contestants Division

感想:  本来是准备练树形dp的,其实树形dp是可以写的,但是这题来个树形搜索就ok了。  题意:给你一棵,(本人感觉M是欺骗性的数据,其实只可能等于n-1),然后减掉上的一个,将分成2个部分,要求最小的2部分和的差得绝对值。 思路:首先看到这里面的数据就发现可能超int型的范围,所以果断用long long,然后那个abs函数也别用,直接自己写,速度更加快。搜索每一个根的时候,用tm

purevegetable 796

树形dppoj 3140 Contestants Division

题目 poj3140 题意: 有一张图,可以把其中一条去掉把图分成个部分,输出最小的个部分的值的绝对差。 思路: 记录全图的总价值cnt; 以结点1为根,dp [ i ] 为记录第 i 个结点向下的连通度。 对于其中一个结点 p ,遍历与它有的结点s1,s2,,,sn, ans=min⁡i=1n∣dp[i]+v[i]−(cnt−(dp[i]+v[i]))∣=min⁡i=1n∣(dp[i]+v[i])∗2−cnt∣ ans = \min_{i=1}^{n}|dp[i]+v[i]-(cnt-(dp[i]

ymxyld的博客 162

POJ 3140 Contestants Division树形DP

题目链接:http://poj.org/problem?id=3140 题意:给你一棵,每个点都有点权,求出去掉一条后剩余的最小权值之差 思路:dp[u]代表以u点为根的子的权值和,这样当去掉u和u的父节点间的那条时,其权值差即为(总权值 - dp[u]) - dp[u]的绝对值,注意这题的数据范围需要用long long,而且ans初始值要给的足够大 ...

Tongqi 785

树形DPPOJ 3140 Contestants Division

通道:http://poj.org/problem?id=3140 题意:一棵n个结点的带权无根,从中一条,使得剩下来的棵子的节点权值之和的绝对值最小,并求出得到的最小绝对值 代码: #include<iostream> #include <cstdio> #include <cstring> #define min(a...

105

poj 3140 Contestants Divisiondp

【题目大意】:给出一棵,每个节点都有一个权值。删除一条之后,问棵子的权值之差的最少为多少。 【解题思路】:利用dfs枚举,记忆化搜索记录下到达当前节点并以当前节点为根的子的权值,记为dp[i];      则我们可以得出,棵子的权值之差就是abs(sum-dp[i]-dp[i])....对于每一个点去min就是答案了。 【代码】: #include #in

Wu is so Water 727

POJ 3140Contestants Division

【题目链接】 点击打开链接 【算法】 树形DP ans = min{ | total - 2 * sum[k] | } (sum为以k为根的子的权值和) 【代码】 #include <algorithm> #include <bitset> ...

131

POJ3140 Contestants Division

题目链接 Contestants Division Time Limit:2000MS Memory Limit:65536K Total Submissions:12935 Accepted:3569 Description In the new ACM-ICPC Regional Contest, a special monitoring ...

Luowaterbi的博客 194

poj 3140 Contestants Division树形dp? dfs计数+枚举)

题目 给n个节点的带权掉其中一,就会变成颗子, 求去某条使得这这颗子的权值之差的绝对值最小。 思路 直接dfs一次,计算所有子的权值总和tot[i] 一条(v, fa),fa是v的父亲节点, 那么v字数总总和为tot[v],显然另一棵子的权值总和就是sum-tot[v], 最总取最小绝对值即可。

D_Double's Journey 1459

Poj 3140 Contestants DivisionDP_树形DP)

题目链接:http://poj.org/problem?id=3140 题目大意:给定一棵n棵节点的,求去某条个分支的最小差异值。 解题思路:树形DP.深搜次,第一次深搜记录从当前节点的子孙节点总数(包括自己),第一次算预处理,复杂度为O(N),第二次利用第一次的结果找去掉某条后的最小差异值,答案需用__int64。其实一切皆模拟,这题只是模拟地比较有规律而已。

1652
上一篇: POJ 2378 Tree Cutting (简单树形DP、删点)
下一篇: 树形 DP 总结
姜团长
博客等级 码龄11年 72粉丝 157原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值