Regional_2011_H Holiday's Accommodation

题目地址: 1 LA 戳这里   2 hdu 2011_Chengdu_H


题目大意:  给你一颗树 ,告诉你每条边的权值,现在每个节点上的人要到其他的地方去,问所有里程加起来最多可以是多少?


先估计一下上界:

对于每一条边: 它作为割边将图分为两部分,假设这两边的人都尽可能的夸过这条边,这样在这条边上的贡献将达到最大。

先转化为有根树后,取2*min(k,n-k)  k是孩子节点的树的size


案例是可以过的,直接敲了 ac 应该是正确的算法 正确性有待证明

LA上直接dfs就可以了

如果是杭电会爆栈  用c++交 + 手动改栈的大小 #proma comment(linker,“/stack1024000000,1024000000”)


代码:

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>

using namespace std;


struct edge
{
    int u;
    int v;
    int w;
};


int min(int a,int b)
{
    return a<b?a:b;
}

edge e[1000005];


vector<int>  G[1000005];
// bool vis[1000005];
int p[1000005];     //    记录父亲节点

int tree_size[1000005];

int n;

void dfs(int u,int fa)
{
    tree_size[u]++;
    int d=G[u].size();
    
    for(int i=0;i<d;i++)
    {
        int v=G[u][i];
        if(v!=fa)
        {
            dfs(v,p[v]=u);
            tree_size[u]+=tree_size[v];
        }
        
        
    }
    
    
    
}



void  init()
{
    for(int i=0;i<1000005;i++)
        G[i].clear();
    
    memset(p,0,sizeof(p));
    memset(tree_size,0,sizeof(tree_size));
    
}
int main()

{
    
    int cas;
    cin>>cas;
    
    
    for(int l=0;l<cas;l++)
    {
        
        init();
        
        cin>>n;
        
        int a,b,c;
        
        for(int i=0;i<n-1;i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            G[a-1].push_back(b-1);
            G[b-1].push_back(a-1);
            
            e[i].u=a-1;
            e[i].v=b-1;
            e[i].w=c;
            
        }
        p[0]=-1;
        dfs(0,-1);
        
        
        
        
        long long ans=0;
        
        for(int i=0;i<n-1;i++)
        {
            int aa=e[i].u;
            int bb=e[i].v;
            
            if(p[aa]==bb)
            {
                ans+=2*min(tree_size[aa],n-tree_size[aa])*e[i].w;
            }
            
            else
            {
                
                ans+=2*min(tree_size[bb],n-tree_size[bb])*e[i].w;
            }
        }
        
        cout<<"Case #"<<l+1<<": "<<ans<<endl;
        
    }
}

关于上界可达正确性的证明 想清楚了子补上来吧

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值