zoukankan      html  css  js  c++  java
  • hdu5044(二分)

    题意:一个树上建两个加油站。使得全部点到达其近期加油站的最大距离最小。

    解法:二分答案。关键时二分时候,要最合理话布局两个点的位置,做法是处理出来树的直径,然后在直径两端分别向中间移动二分的x步的两个点布下加油站。

    贪心能够证明正确性;


    代码:

    /******************************************************
    * @author:xiefubao
    *******************************************************/
    #pragma comment(linker, "/STACK:102400000,102400000")
    #include <iostream>
    #include <cstring>
    #include <cstdlib>
    #include <cstdio>
    #include <queue>
    #include <vector>
    #include <algorithm>
    #include <cmath>
    #include <map>
    #include <set>
    #include <stack>
    #include <string.h>
    //freopen ("in.txt" , "r" , stdin);
    using namespace std;
    
    #define eps 1e-8
    #define zero(_) (_<=eps)
    const double pi=acos(-1.0);
    typedef long long LL;
    const int Max=200010;
    const LL INF=0x3FFFFFFF;
    vector<int> vec[Max];
    int n;
    vector<int> diameter;
    int rem[Max];
    int rem1[Max];
    int rem2[Max];
    int dis[Max];
    int st,en;
    int dui[Max*2];
    int now=0;
    int count1=10;
    void dfs(int u)
    {
        memset(rem,0,sizeof rem);
        rem[u]=-1;
        int left=0;
        int right=1;
        dui[0]=u;
        dis[u]=0;
        while(left<right)
        {
            for(int i=0; i<vec[dui[left]].size(); i++)
            {
                if(rem[vec[dui[left]][i]]==0)
                {
                    rem[vec[dui[left]][i]]=dui[left];
                    dis[vec[dui[left]][i]]=dis[dui[left]]+1;
                    dui[right++]=vec[dui[left]][i];
                }
            }
            left++;
        }
    }
    
    void ran1(int u,int* re)
    {
        int left=0;
        int right=1;
        dui[0]=u;
        dis[u]=0;
        re[u]=count1;
        while(left<right)
        {
            if(dis[dui[left]]<now)
            for(int i=0; i<vec[dui[left]].size(); i++)
            {
                if(re[vec[dui[left]][i]]!=count1)
                {
                    re[vec[dui[left]][i]]=count1;
                    dis[vec[dui[left]][i]]=dis[dui[left]]+1;
                    if(dis[vec[dui[left]][i]]<now)
                        dui[right++]=vec[dui[left]][i];
                }
            }
            left++;
        }
    }
    
    bool OK(int middle)
    {
        count1++;
        now=middle;
        ran1(diameter[middle],rem1);
        ran1(diameter[diameter.size()-1-middle],rem2);
        for(int i=1; i<=n; i++)
        {
            if(rem1[i]!=count1&&rem2[i]!=count1)
                return false;
        }
        return true;
    }
    int main()
    {
        int t;
        cin>>t;
        while(t--)
        {
            for(int i=1;i<Max;i++)
            vec[i].clear();
            diameter.clear();
            scanf("%d",&n);
            for(int i=0; i<n-1; i++)
            {
                int a,b;
                scanf("%d%d",&a,&b);
                vec[a].push_back(b);
                vec[b].push_back(a);
            }
            dfs(1);
            int d=0;
            for(int i=1; i<=n; i++)
            {
                if(dis[i]>d)
                {
                    d=dis[i];
                    st=i;
                }
            }
            dfs(st);
            d=0;
            for(int i=1; i<=n; i++)
            {
                if(dis[i]>d)
                {
                    d=dis[i];
                    en=i;
                }
            }
            while(en!=-1)
            {
                diameter.push_back(en);
                en=rem[en];
            }
            int left=0,right=diameter.size();
            while(left<=right)
            {
                int middle=(left+right)/2;
                if(!OK(middle))
                {
                    left=middle+1;
                }
                else
                {
                    right=middle-1;
                }
            }
            int a=diameter[left];
            int b=diameter[diameter.size()-1-left];
            if(a==b)
            {
                a=b==n?n-1:b+1;
            }
            //cout<<diameter.size()<<" "<<OK(0)<<OK(1)<<endl;
            cout<<left<<" "<<a<<" "<<b<<'
    ';
        }
        return 0;
    }
    /*
    34
    4
    1 2
    1 3
    1 4
    5
    1 2
    2 3
    3 4
    4 5
    3
    1 2
    2 3
    */
    

  • 相关阅读:
    Codeforces Round #518 Div. 1没翻车记
    BZOJ4310 跳蚤(后缀数组+二分答案)
    后缀数组备忘
    洛谷 P3573 [POI2014]RAJ-Rally 解题报告
    洛谷 P1503 鬼子进村 解题报告
    洛谷 P2375 [NOI2014]动物园 解题报告
    洛谷 P2797 Facer的魔法 解题报告
    【模板】三分法
    那些神奇的DP建模
    洛谷 P1136 迎接仪式 解题报告
  • 原文地址:https://www.cnblogs.com/jhcelue/p/6907039.html
Copyright © 2011-2022 走看看