http://acm.hdu.edu.cn/showproblem.php?pid=2242
题意:给你一个有N个点,M条边的无向图,并给没个结点一个权值,要求去掉所有边中的一条,将图分成两部分,求此时的两个图的权值差的最小值。
思路:先对原图进行缩点,就可以得到一棵树,再用一个树形dp求出最小的权值差。注意重边的处理。
代码:
#include<stdio.h> #include<string.h> #include<math.h> #include<stdlib.h> const int MAXN = 50010 ; const int MAXM = 100010 ; int N ,M ; int num[MAXN] ; struct Node{ int num ,next ; }edge[MAXM*2] ; int root[MAXN] ,e_cnt ; struct Node1{ int num ,next ; }ex[MAXM*2]; int r[MAXN] , r_cnt ; int sum[MAXN] ,tot ,ans; void init(){ memset(root, -1, sizeof(root)); e_cnt = 0 ; r_cnt = 0 ; memset(r, -1, sizeof(r)); } void add(int a, int b ){ edge[e_cnt].num = b ; edge[e_cnt].next = root[a]; root[a] = e_cnt++ ; } int dfn[MAXN] , low[MAXN] , stack[MAXN] ,id[MAXN]; int top , idx , cnt ; void tarjin(int x, int pre){ low[x] = dfn[x] = ++idx ; stack[top++] = x ; bool f = 1 ; for(int i=root[x];i!=-1;i=edge[i].next){ int u = edge[i].num ; if(u==pre && f){ //避免重边,第一次的时候直接跳过 f = 0 ; continue ; } if( dfn[u] == -1){ tarjin(u,x); if( low[u] < low[x]) low[x] = low[u] ; else if( low[u] > dfn[x] ){ for( stack[top]=-1 ;stack[top]!=u ;){ top-- ; int v = stack[top] ; id[ v ] = cnt ; } cnt ++ ; } } else if( dfn[u] < low[x]) low[x] = dfn[u] ; } } void add1(int a ,int b){ ex[r_cnt].num = b ; ex[r_cnt].next = r[a] ; r[a] = r_cnt++ ; } int dfs(int u,int pre){ int res = sum[u] ; for(int i=r[u];i!=-1;i=ex[i].next){ int v = ex[i].num ; if(v == pre) continue ; int temp = dfs(v,u) ; res += temp ; } if(ans > abs( tot-res*2) ) ans = abs( tot - res*2 ) ; return res ; } void solve(){ top = idx = cnt = 0 ; memset(dfn , -1 ,sizeof(dfn)); memset(id , 0 ,sizeof(id)); memset(sum , 0, sizeof(sum)); cnt = 1 ; for(int i=1;i<=N;i++){ if( dfn[i] == -1 ){ tarjin(i, -1) ; } } if(cnt == 1){ printf("impossible\n") ; return ; } for(int i=1;i<=N;i++){ sum[ id[i] ] += num[i] ; } for(int i=1;i<=N;i++){ for(int j=root[i] ;j!=-1;j=edge[j].next){ int v = edge[j].num ; if( id[i] != id[v] ){ add1( id[i],id[v] ) ; } } } ans = (1<<30) ; dfs(1,-1); printf("%d\n",ans) ; } int main(){ int a ,b ; while(scanf("%d%d",&N,&M) == 2){ tot = 0; for(int i=1;i<=N;i++){ scanf("%d",&num[i]); tot += num[i]; } init() ; for(int i=1;i<=M;i++){ scanf("%d%d",&a,&b); a++ ;b ++ ; add(a,b); add(b,a); } solve() ; } return 0 ; }