zoukankan      html  css  js  c++  java
  • 10.20T3 DLZ常数剪枝+枚举边+带权重心

    Description




     
     
     
     
    DLZ常数史称杜林哲常数,用来优化树中最值以及枚举边的问题
    DLZ常数的计算方法是看树的规模,再进行一系列的运算可以得到
    在这道题里面DLZ常数可以控制在11~20之间,就可以剪枝了
    做法:
    枚举每一条边,找两边子树的带权重心,此时必定最优,然后计算出相应的值然后进行比较
    DLZ剪枝定律:当两边子树的比值为一个DLZ常数范围的时候,剪枝必定成立并且可以优化时间复杂度
    这个定律在bashu联考的时候被DLZ提出
    复杂度O(n^2/DLZ)
    code:
     1 #include<iostream>
     2 #include<cstdio>
     3 #define N 100005
     4 using namespace std;
     5 struct node{
     6     int u,v;
     7 }e[N];
     8 int first[N],nxt[N],cnt;
     9 void add(int u,int v){
    10     e[++cnt].u=u;
    11     e[cnt].v=v;
    12     nxt[cnt]=first[u];
    13     first[u]=cnt;
    14 }
    15 int siz[N],root,a[N],mxsiz,mark;
    16 int getroot(int x,int father){
    17     siz[x]=a[x];
    18     int max0=0;
    19     for(int i=first[x];i;i=nxt[i]){
    20         int v=e[i].v;
    21         if(v==father)continue;
    22         getroot(v,x);
    23         siz[x]+=siz[v];
    24         max0=max(max0,siz[v]);
    25     }
    26     max0=max(max0,mxsiz-siz[x]);
    27     if(max0<mark){
    28         root=x;
    29         mark=max0;
    30     }
    31 }
    32 int temp,dis[N],End;
    33 void getdis(int x,int father){
    34     temp+=dis[x]*a[x];
    35     for(int i=first[x];i;i=nxt[i]){
    36         int v=e[i].v;
    37         if(v==father)continue;
    38         if(v==End)continue;
    39         dis[v]=dis[x]+1;
    40         getdis(v,x);
    41     }
    42 }
    43 int s[N],suma,ans=0x3f3f3f3f;
    44 void cal(int x,int y){
    45 //    cout<<"left->"<<x<<" right->"<<y<<endl;
    46     temp=0;
    47     mxsiz=s[x],mark=mxsiz;
    48 //    cout<<"mxsiz->"<<mxsiz<<endl;
    49     getroot(x,y),End=y;
    50     dis[root]=0;
    51     getdis(root,0);
    52     mxsiz=suma-s[x],mark=mxsiz;
    53     getroot(y,x),End=x;
    54     dis[root]=0;
    55     getdis(root,0);
    56     ans=min(temp,ans);
    57 }
    58 void work(int x,int father){
    59     s[x]=a[x];
    60     for(int i=first[x];i;i=nxt[i]){
    61         int v=e[i].v;
    62         if(v==father)continue;
    63         work(v,x);
    64         s[x]+=s[v];
    65         if(s[v]*20<suma)continue;
    66         cal(v,x);
    67     }
    68 }
    69 int main(){
    70     int n;
    71     cin>>n;
    72     for(int i=1;i<n;i++){
    73         int u,v;
    74         cin>>u>>v;
    75         add(u,v);
    76         add(v,u);
    77     }
    78     for(int i=1;i<=n;i++){
    79         cin>>a[i];
    80         suma+=a[i];
    81     }
    82     work(1,0);
    83     cout<<ans;
    84     return 0;
    85 }

    over

  • 相关阅读:
    结对编程项目作业2-结对编项目设计文档
    20170914-构建之法:现代软件工程-阅读笔记
    课后作业-阅读任务-阅读提问-1
    GIT 的使用方法
    团队-井字棋-需求分析
    结对-贪吃蛇-需求分析
    python_基础_0
    Unix_07_文件系统高级操作_2
    Unix_06_文件系统高级操作_1
    Unix_05_文件系统高级操作_0
  • 原文地址:https://www.cnblogs.com/saionjisekai/p/9822126.html
Copyright © 2011-2022 走看看