您的位置:首页 > 其它

POJ-3140 Contestants Division (树)

2016-04-24 21:55 274 查看
题目大意:一棵树,带点权。将这棵树分成两部分,找出使得两部分的点权和的差最小。

题目分析:直接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;
}


  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: