题意:
有n个城市,构成一棵树,每个城市有v个人,要求断开树上的一条边,使得两个连通分量中的人数之差最小。问差的绝对值。(注意本题的M是没有用的,因为所给的必定是一棵树,边数M必定是n-1)
思路:
考虑当前节点t,当断开t与父亲的边时,“子树t中的人数”与“剩下的人数”之差的绝对值若最小,则为答案。
//#include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <map>
#include <deque>
#include <algorithm>
#include <vector>
#include <iostream>
#define pii pair<int,int>
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define abs(x) ((x)<0?-(x):(x))
#define INF 2147483647
#define LL long long
using namespace std;
const double PI = acos(-1.0);
const int N=;
int edge_cnt, head[N], w[N];
LL ans, sum;
struct node
{
int from, to, next;
node(){};
node(int from,int to,int next):from(from),to(to),next(next){};
}edge[N*]; void add_node(int from,int to)
{
edge[edge_cnt]=node(from,to,head[from]);
head[from]=edge_cnt++;
} LL DFS(int t,int far) //枚举删除t头上的边
{
node e;
LL cnt=;
for(int i=head[t]; i!=-; i=e.next)
{
e=edge[i];
if(e.to==far) continue;
cnt+=DFS(e.to, t);
}
cnt+=w[t]; //本子树的人数
ans=min(ans, abs( *cnt-sum ));
return cnt;
} int main()
{
//freopen("input.txt", "r", stdin);
int a, b, n, m, Case=;
while(scanf("%d%d",&n,&m), n+m)
{
sum=edge_cnt=;
memset(head,-,sizeof(head)); for(int i=; i<=n; i++)
{
scanf("%d",&w[i]);
sum+=w[i];
}
ans=sum;
for(int i=; i<m; i++)
{
scanf("%d%d",&a,&b);
add_node(a,b);
add_node(b,a);
}
DFS(,-);
printf("Case %d: %lld\n", ++Case, ans);
}
return ;
}
AC代码