POJ 3140 Contestants Division (DFS)

本文介绍了一种使用树形动态规划解决特定类型问题的方法。给定一棵无根树及各节点的值,目标是在树上切一刀使两部分的节点值之和的差最小。文章通过代码实现展示了如何通过递归遍历树结构并利用动态规划计算最优解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:给定一棵无根树,每个节点有一个值, 你可以在任意两节点间划一下,使得分开的两棵子树的值的差最小。
题解:若所有节点的值的总和为奇数,那么任意划一下一定得一奇一偶的两棵子树,值之差一定是奇数且>=1。若总值为偶数,那么值之差一定为偶数且>=0。

#include <cmath>
#include <iostream>
using namespace std;

#define N 100005
#define lint __int64
#define INF 9999999999999 //开得足够大才行 

int m, n, k;
int num[N];
bool vis[N];
lint dp[N], ans, sum;

struct TreeNode
{
	int id;
	TreeNode *next;
}; 

TreeNode node[N];
TreeNode store[2*N];

inline lint abl ( lint a )
{
	return a < 0 ? -a : a;
}

inline lint min ( lint a, lint b )
{
	return a < b ? a : b;
}

void add ( int u, int v )
{
	TreeNode *p = &store[k++];
	p->id = v;
	p->next = node[u].next;
	node[u].next = p;
}

void dfs ( int u )
{
	vis[u] = 1;
	dp[u] = num[u];
	if ( ans < 2 ) return; // 优化一下
	TreeNode *p = node[u].next; 

	while ( p != NULL )
	{
		int v = p->id;
		if ( ! vis[v] )
		{
			dfs ( v );
			dp[u] += dp[v];
			if ( ans < 2 ) return;
		}
		p = p->next;
	}
	ans = min ( ans, abl(sum-dp[u]*2) );
}

int main()
{
	int i, u, v, Case = 0;
	while ( scanf("%d %d",&n,&m) )
	{
		if ( ! m && ! n ) break;

		k = sum = 0;
		memset(vis,0,sizeof(vis));
		memset(node,NULL,sizeof(node));
		memset(store,NULL,sizeof(store));

		for ( i = 1; i <= n; i++ )
		{
			scanf("%d",&num[i]);
			sum += num[i];
		}

		while ( m-- )
		{
			scanf("%d %d",&u,&v);
			add ( u, v );
			add ( v, u );
		}
		ans = INF;
		dfs ( 1 );
		printf("Case %d: %I64d\n", ++Case, ans );
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值