• 《算法竞赛进阶指南》0x45点分治


    题目链接:http://poj.org/problem?id=1741

    给定一棵树,问树中长度小于等于K的点对的数量,经典的点分治问题,将这样的点对看做两种——经过根节点和不经过根节点,经过根结点的,可以通过子树划分,记录所有节点,然后按照指针方式进行搜索,可以卡过,时间复杂度大约是O(nlog^2n)。

    代码:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<string.h>
    using namespace std;
    const int maxn = 10010;
    bool v[maxn],w[maxn];
    int d[maxn],b[maxn],a[maxn],tot,cnt[maxn];
    int head[maxn],nxt[maxn<<1],len[maxn<<1],ver[maxn<<1],t;//存图以及边的数量 
    int n,k,s[maxn],Ans;
    int ans,pos;//记录树的重心以及最大的子树的大小 
    void addedge(int u,int v,int w){
        ver[++t]=v;
        len[t]=w;
        nxt[t]=head[u];
        head[u]=t;
    }
    void dfs_find(int S,int x){
        v[x]=1;
        s[x]=1;
        int max_part=0;
        for(int i=head[x];i;i=nxt[i]){
            int y=ver[i];
            if(v[y] || w[y])continue;//访问过或者是被删除
            dfs_find(S,y);
            s[x]+=s[y];
            max_part=max(max_part,s[y]);//找到删除x后最大的子树 
        }
        max_part=max(max_part,S-s[x]);
        if(max_part<ans){
            ans=max_part;
            pos=x;//重心 
        }
    }
    void dfs(int x){
        v[x]=1;
        for(int i=head[x];i;i=nxt[i]){
            int y=ver[i];
            int z=len[i];
            if(v[y] || w[y])continue;
            b[y]=b[x];
            a[++tot]=y;
            ++cnt[b[y]];
            d[y]=d[x]+z;
            dfs(y);
        }
    }
    bool cmp(int i,int j){//按照节点距离根节点的路径长度进行排序 
        return d[i]<d[j];
    }
    void work(int S,int x){
        memset(v,0,sizeof(v));
        ans=S;
        dfs_find(S,x);//找到重心 
        memset(d,0,sizeof(d));
        memset(cnt,0,sizeof(cnt));
        memset(v,0,sizeof(v));
        tot=1;//处理根节点 
        a[1]=pos;
        b[pos]=pos;
        w[pos]=1;//根节点被删除 
        ++cnt[pos];
    
    //    访问pos的子树 
        for(int i=head[pos];i;i=nxt[i]){
            int y=ver[i];
            int z=len[i];
            if(v[y] || w[y])continue;
            a[++tot]=b[y]=y;
            ++cnt[b[y]];
            d[y]=z;//设置每个点距离根节点的距离
            dfs(y); //对每棵子树进行访问 
        }
        sort(a+1,a+tot+1,cmp);
        int l=1,r=tot;
        --cnt[b[a[1]]];//初始时刻维护的是[2,tot]区间上的信息
        while(l<r){
            while(d[a[l]]+d[a[r]]>k){
                cnt[b[a[r]]]--;
                r--;
            } 
            Ans+=r-l-cnt[b[a[l]]];//将同一棵子树上的r端减去 
            --cnt[b[a[l+1]]];//维护的区间发生变化 
            l++; 
        }
        int now=pos;//暂存这个重心,因为pos在处理子树的时候会变化 
        for(int i=head[now];i;i=nxt[i]){
            int y=ver[i];
            if(w[y])continue;
            work(s[y],y);//对每一个子树递归求解Ans 
        }
    }
    void solve(){
        t=0;
        memset(head,0,sizeof(head));
        for(int i=1;i<n;i++){
            int x,y,z;
            scanf("%d %d %d",&x,&y,&z);
            addedge(x,y,z);
            addedge(y,x,z);
        }
        memset(w,0,sizeof(w));
        Ans=0;
        work(n,1);//从任何一个点开始,每次都找重心进行操作
        cout<<Ans<<endl; 
    }
    int main(){
        while(cin>>n>>k && n && k)solve();
        return 0;
    }
    每一个不曾起舞的日子,都是对生命的辜负。
  • 相关阅读:
    virtualbox使用相关问题
    mac os中的一些快捷键使用及基础软件安装
    U盘安装CentOS7
    Netbeans8下 Weblogic EJB案例
    Linux Weblogic 数据源 TimesTen配置
    JDBC操作TimesTen
    Red Hat TimesTen安装记录
    使用Protractor进行AngularJS e2e测试案例
    基于Karma和Jasmine的AngularJS测试
    protractor protractor.conf.js [launcher] Process exited with error code 1 undefined:1190
  • 原文地址:https://www.cnblogs.com/randy-lo/p/13358484.html
Copyright © 2020-2023  润新知