POJ-3140 Contestants Division (树)
题目大意:一棵树,带点权。将这棵树分成两部分,找出使得两部分的点权和的差最小。
题目分析:直接dfs即可。找出每棵子树u的点权和size(u),如果以u和它的父节点之间的边为界,那么两边的点权和分别为sum-size(u)和size(u)。
代码如下:
# include<iostream> # include<cstdio> # include<cstring> # include<vector> # include<queue> # include<list> # include<set> # include<map> # include<string> # include<cmath> # include<cstdlib> # include<algorithm> using namespace std; # define LL long long const int N=1005; const int INF=1000000000; const LL oo=0x7fffffffffffffff; struct Edge { int to,nxt; }; Edge e[N*200]; int n,m,cnt; int head[N*100]; int w[N*100]; LL sum; LL size[N*100]; int vis[N*100]; void add(int u,int v) { e[cnt].to=v; e[cnt].nxt=head[u]; head[u]=cnt++; } void init() { cnt=0; memset(vis,0,sizeof(vis)); memset(head,-1,sizeof(head)); sum=0; for(int i=1;i<=n;++i){ scanf("%d",w+i); sum+=(LL)w[i]; } int a,b; for(int i=0;i<m;++i){ scanf("%d%d",&a,&b); add(a,b); add(b,a); } } void dfs(int u,int fa) { size[u]=w[u]; vis[u]=1; for(int i=head[u];i!=-1;i=e[i].nxt){ int v=e[i].to; if(v==fa||vis[v]) continue; dfs(v,u); size[u]+=size[v]; } } LL solve() { dfs(1,-1); LL ans=oo; for(int i=1;i<=n;++i){ LL t=max(sum-size[i],size[i])-min(sum-size[i],size[i]); if(t<ans) ans=t; } return ans; } int main() { int cas=0; while(scanf("%d%d",&n,&m)&&(n+m)) { init(); printf("Case %d: %lld\n",++cas,solve()); } return 0; }