POJ 3140 Contestants Division

题目大意:

n个点,每个点有个权值,m条边,形成一棵树,这道题里面,m就是坑爹的,实际上就是 m = n-1 ,不考虑它也没问题 , 写在这里吓唬人的

只能建一条通信道 , 也就是找到一条边作为通信通道,然后这个通信通道分割了2棵树,求得到两棵树权值之和相差的值最小

这里数据比较大,要用到 long long

开始对于m,n的数据给定完全不理解,看了别人的说这个没用,就好做很多了

用sum[i]记录 i 对应的树中权值总和

dfs一次即可,通过sum[i]来解决问题

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 using namespace std;
 5 
 6 typedef long long ll;
 7 const int N = 100005;
 8 
 9 int first[N] , k , val[N];
10 ll sum[N] , all;
11 
12 struct Edge{
13     int y , next , flag;
14 }e[N<<1];
15 
16 ll my_abs(ll x)
17 {
18     return x>=0?x:-x;
19 }
20 
21 void add_edge(int x , int y)
22 {
23     e[k].y = y , e[k].next = first[x] , e[k].flag = false;
24     first[x] = k++;
25 }
26 
27 void dfs(int u , int fa)
28 {
29     sum[u] = val[u];
30     for(int i=first[u] ; i!=-1 ; i=e[i].next){
31         int v = e[i].y;
32         if(v == fa) continue;
33         dfs(v , u);
34         e[i].flag = true;
35         sum[u]+=sum[v];
36     }
37 }
38 
39 int main()
40 {
41   //  freopen("a.in" , "r" , stdin);
42     int n , m , x , y , cas=0;
43     while(scanf("%d%d" , &n , &m) , n||m){
44         memset(first , -1 , sizeof(first));
45         k=0 , all = 0;
46         for(int i=1 ; i<=n ; i++)
47         {
48             scanf("%d" , val+i);
49             all += val[i];
50         }
51 
52         for(int i=0 ; i<m ; i++){
53             scanf("%d%d" , &x , &y);
54             add_edge(x , y);
55             add_edge(y , x);
56         }
57 
58         dfs(1 , -1);
59         ll ans = 100000000;
60         ans = ans*ans;
61       /*  for(int i=1 ; i<=n ; i++)
62             cout<<"i: "<<i<<" "<<sum[i]<<endl;*/
63         for(int i=0 ; i<k ; i++){
64             if(!e[i].flag) continue;
65             ll t = my_abs(all - sum[e[i].y] - sum[e[i].y]);
66             ans = min(ans , t);
67         }
68         printf("Case %d: %lld
" , ++cas , ans);
69     }
70     return 0;
71 }
原文地址:https://www.cnblogs.com/CSU3901130321/p/4234170.html