![poj 3140 Contestants Division [DFS] poj 3140 Contestants Division [DFS]](https://image.shishitao.com:8440/aHR0cHM6Ly9ia3FzaW1nLmlrYWZhbi5jb20vdXBsb2FkL2NoYXRncHQtcy5wbmc%2FIQ%3D%3D.png?!?w=700&webp=1)
题意:一棵树每个结点上都有值,现删掉一条边,使得到的两棵树上的数值和差值最小。
思路:这个题我直接dfs做的,不知道树状dp是什么思路。。一开始看到数据规模有些后怕,后来想到long long 可以达到10^18,我突然就释然了。
整体思路就是,先记录下整棵树的数值之和tot,然后对这棵树进行一遍dfs,每个结点都维护一个num值,num[x]表示结点x和它子树上的数值和。每求出一个结点的num值,就计算下tot - num[x]和num[x]的差值。dfs结束后最小的差值即为结果。
另外,要注意的一点是,如果用res来存储最后结果,初始化应为无穷大,而因为它是long long类型,可以初始化为0x3f3f3f3f3f3f3f3f。如果你还是按照int的大小来初始化为无穷大,会发现wa,就是这么回事。。。
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define maxn 100005
#define maxp 1000005
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std; struct node
{
int v, next;
}edge[maxp];
int num_edge, head[maxn];
void init_edge()
{
num_edge = ;
memset(head, -, sizeof(head));
}
void addedge(int a,int b)
{
edge[num_edge].v = b;
edge[num_edge].next = head[a];
head[a] = num_edge++;
} long long dif(long long a,long long b)
{
return (a > b) ? a - b : b - a;
} int stu[maxn], n, m;
bool vis[maxn];
long long num[maxn], tot, res;
void dfs(int x)
{
num[x] = stu[x];
vis[x] = ;
for (int i = head[x]; i != -; i = edge[i].next)
{
int v = edge[i].v;
if (vis[v]) continue;
dfs(v);
num[x] += num[v];
}
res = min(res, dif(num[x], tot - num[x]));
}
int main()
{
int cas = ;
while (~scanf("%d%d", &n, &m) && n && m)
{
tot = ;
for (int i = ; i <= n; i++)
{
scanf("%d",&stu[i]);
tot += stu[i];
}
init_edge();
memset(vis, , sizeof(vis));
for (int i = ; i <= m; i++)
{
int a, b;
scanf("%d%d", &a, &b);
addedge(a, b);
addedge(b, a);
}
res = inf;
dfs();
printf("Case %d: %lld\n", cas++, res);
}
return ;
}