题目大意:
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 }