题意: 给n个节点的带权树,删掉其中一边,就会变成两颗子树,
求删去某条边使得这这两颗子树的权值之差的绝对值最小。
思路:dfs一遍,用ens[i]表示i的子树的权值和(包括num[i])
删去edge(to,fa),fa是to的父节点,to的子树权值和为ens[to],那么另一颗子树的权值和为sum-ens[to]
答案ans=sum-ens[to]-ens[to]
因为用dfs递推的缘故直接用ens表示相应的ens[to];
遍历全部节点to即可
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int inf=-1e9;
const int N=1e5+8;
ll ans;
int head[2*N];
int tot;
ll sum;
int num[2*N];
ll Abs(ll a)
{
return a>0?a:-a;
}
struct Edge
{
int to;
int next;
}edge[2*N];
void init()
{
memset(head,-1,sizeof(head));
tot=0;
sum=0;
}
void add_edge(int u,int v)
{
edge[tot].to=v;
edge[tot].next=head[u];
head[u]=tot++;
}
ll dfs(int u,int fa)
{
ll ens=num[u];
for(int i=head[u];i!=-1;i=edge[i].next)
{
int to=edge[i].to;
if(to==fa)continue;
ens+=dfs(to,u);
}
ans=min(ans,Abs(sum-ens-ens));
return ens;
}
int main()
{
int i,j,k,n,m,u,v;
int cnt=1;
while(cin>>n>>m){
if(n==0&&m==0)break;
init();
for(i=1;i<=n;i++){
cin>>num[i];
sum+=num[i];
}
for(i=0;i<m;i++){
cin>>u>>v;
add_edge(u,v);
add_edge(v,u);
}
ans=sum;
dfs(1,-1);
cout<<"Case "<<cnt++<<": "<<ans<<endl;
}
return 0;
}