hdu3140(树形dp)
src : http://poj.org/problem?id=3140
题意:选择一条树边断开,使得分成的两部分的总点权差最小,输出最小值
就直接预处理每一个点及其子树的总点权
枚举一个点和其父亲断开,取个最优值就好了
注意long long
#include <iostream> #include<stdio.h> #include<cstdlib> #include<algorithm> #include<cmath> #include<functional> #include<utility> #include<string> #include<string.h> #include<vector> #include<iomanip> #include<stack> #include<queue> using namespace std; #define FOR(i,a,b) for(int i=a;i<=b;i++) #define Max(a,b) a=max(a,b) #define Min(a,b) a=min(a,b) //const int inf=0x3f3f3f; const long long inf=1e18; #define siz 100005 int n,m,head[siz],Enum,pre[siz]; long long sum[siz],w[siz],all; struct{ int to,ne; }edge[siz<<1]; void init() { Enum=0; all=0; memset(head,-1,sizeof(head)); memset(sum,0,sizeof(sum)); } void add_edge(int a,int b) { edge[Enum].to=b; edge[Enum].ne=head[a]; head[a]=Enum++; } void dfs(int u,int fa) { pre[u]=fa; sum[u]=w[u]; for(int i=head[u];i!=-1;i=edge[i].ne){ int v=edge[i].to; if(v==fa)continue; dfs(v,u); sum[u]+=sum[v]; } } int main() { std::ios::sync_with_stdio(false); int cas=0; while(scanf("%d %d",&n,&m)!=EOF&&(n||m)){ cas++; init(); for(int i=1;i<=n;i++){scanf("%d",&w[i]);all+=w[i];} int a,b; for(int i=1;i<=m;i++){ scanf("%d %d",&a,&b); add_edge(a,b);add_edge(b,a); } dfs(1,-1); //for(int i=1;i<=n;i++)printf("%I64d ",sum[i]);printf("\n");system("pause"); long long tmp,mi=inf; for(int i=2;i<=n;i++){ if(sum[i]>all-sum[i])tmp=sum[i]-all+sum[i]; else tmp=all-sum[i]-sum[i]; //printf("i==%d :%lld\n",i,tmp); if(tmp<mi){mi=tmp;} } printf("Case %d: %lld\n",cas,mi); } return 0; } /* 7 6 1 2 100 4 100 3 2 1 2 2 7 3 7 4 6 6 2 5 7 */

浙公网安备 33010602011771号