您的位置:首页 > 其它

POJ 3140 Contestants Division 树形DP

2015-09-21 13:24 344 查看
题意:

有一棵树,有点权,你可以选择一条边删除,要求删除后形成的2棵子树的权值的差的绝对值最小

输出这个最小值

本来是简单题,一个数组siz

siz[i]表示以i为根的子树的节点的权值之和

然后遍历一遍,找到最小值即可。

注意:

0.点权要long long

1.由于点权之和是long long 的,你在求最小值的时候,初始化ret,

要初始化为ret=0x3f3f3f3f3f3f3f3f,而不能是0x3f3f3f3f

2.输入的数据描述的是n m

(1 ≤ N ≤ 100000, 1 ≤ M ≤ 1000000)

n表示节点的个数,m表示边的个数

然后我就呆了,题目明明说了这是一棵树啊,也就是边数为n-1啊,这里弄个m<= 1000000是什么?

然后想想才知道,这是唬人的,数据一定会保证m=n-1的,被骗了,然后还以为自己读错题意了,又看了很久的题目

3.这里的abs()函数要自己写,因为cmath的abs()函数是int abs()的,在这里不适合,会CE

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>

#define ll long long

using namespace std;

const int maxn=1e5+10;
const ll inf=0x3f3f3f3f3f3f3f3f;

struct Edge
{
int to,next;
};
Edge edge[maxn<<1];
int tot;
int head[maxn];

ll val[maxn];
ll siz[maxn];
ll sum;

void init()
{
memset(head,-1,sizeof head);
tot=0;
sum=0;
}

void addedge(int u,int v)
{
edge[tot].to=v;
edge[tot].next=head[u];
head[u]=tot++;
}

ll solve(int );

int main()
{
int cas=1;
int n,m;
while(scanf("%d %d",&n,&m)){
if(!n&&!m)
break;
printf("Case %d: ",cas++);
init();
for(int i=1;i<=n;i++){
scanf("%lld",&val[i]);
sum+=val[i];
}

for(int i=1;i<=m;i++){
int u,v;
scanf("%d %d",&u,&v);
addedge(u,v);
addedge(v,u);
}
printf("%lld\n",solve(n));
}
return 0;
}

void dfs(int u,int pre)
{
siz[u]=val[u];
for(int i=head[u];~i;i=edge[i].next){
int v=edge[i].to;
if(v==pre)
continue;
dfs(v,u);
siz[u]+=siz[v];
}
}

ll solve(int n)
{
//printf("eee\n");
dfs(1,-1);

ll ret=inf;
for(int i=2;i<=n;i++){
ll cnt=sum-2*siz[i];
if(cnt<0)
cnt*=(-1);
if(cnt<ret)
ret=cnt;
}
return ret;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: