poj 3140 Contestants Division

来源:互联网 发布:餐厅进销存软件 编辑:程序博客网 时间:2024/05/28 09:31

 感想:  本来是准备练树形dp的,其实树形dp是可以写的,但是这题来个树形搜索就ok了。

 题意:给你一棵树,(本人感觉M是欺骗性的数据,其实只可能等于n-1),然后减掉树上的一个边,将树分成2个部分,要求最小的2部分和的差得绝对值。

思路:首先看到这里面的数据就发现可能超int型的范围,所以果断用long long,然后那个abs函数也别用,直接自己写,速度更加快。搜索每一个根的时候,用tmp表示根节点与其子孙的权值和,min(ans,test(sum-2*tmp))  (test是本人自己写的abs函数,不规范,千万别学我,你们自己用重载吧。)  然后就没然后了……

看代码吧,只要写过树形dp的应该都能理解。

INF千万别定义int型的最大,本人就因为这个wa了一次。

#include<cmath>#include<cstdio>#include<cstring>#include<iostream>#define N 100100#define INF 1000000000000000   #define min(a1,b1) (a1)>(b1)?(b1):(a1)using namespace std;int n,m,tot;long long sum,ans,cost[N];int head[N];bool vis[N];struct Node {int to,next;};Node edge[4*N];void add_edge(int a,int b){    edge[tot].to = b;    edge[tot].next = head[a];    head[a] = tot++;}long long test(long long x){    if(x<0)     x *= -1;    return x;}long long dfs(int x){   long long tmp = cost[x];   if(head[x]==-1)   {    ans = min(ans,test(sum-2*tmp));    return tmp;   }   for(int i=head[x];i!=-1;i=edge[i].next)   {       int f = edge[i].to;       if(vis[f])       continue;       vis[f] = true;       long long g = dfs(f);       tmp += g;   }   ans = min(ans,test(sum-2*tmp));   return tmp;}int main(void){    int v = 0;    while(cin>>n>>m,n||m)    {       memset(vis,false,sizeof(vis));       memset(head,-1,sizeof(head));      sum = 0;  tot = 0; ans = INF;     for(int i=1;i<=n;++i)     {      scanf("%d",&cost[i]);      sum += cost[i];     }     for(int i=1;i<=m;++i)     {         int a,b;         scanf("%d %d",&a,&b);         add_edge(a,b);         add_edge(b,a);     }     vis[1] = true;     dfs(1);     cout<<"Case "<<++v<<": ";     cout<<ans<<endl;    }    return 0;}


原创粉丝点击