• 3兔子


    【问题描述】

    在一片草原上有N兔子窝,每个窝里住着一只兔子,有M条路径连接这些。更特殊地是,至多只有一个兔子窝3条或更多的路径与它相连,其它的兔子窝只有1条或2条路径与其相连。换句话讲,这些兔子窝之前路径构成一张N个点、M条边的无向连通图,而度数大于2的点至多有1个。

    兔子们决定把其中K兔子窝扩建成临时避难所。当危险来临时,每只兔子均会同时前往距离它最近的避难所躲避,路程中花费的时间在数值上等于经过的路径条数。为了在最短的时间内让所有兔子脱离危险,请你安排一种建造避难所的方式,使最后一只到达避难所的兔子所花费的时间尽量少。

    【输入】

    第一行有3个整数N,M,K,分别表示兔子窝的个数、路径数、计划建造的避难所数。

    接下来M行每行三个整数x,y,表示第x兔子窝和第y兔子窝之间有一条路径相连。任意两个兔子窝之间至多只有1条路径。

    【输出】

    一个整数,表示最后一只到达避难所的兔子花费的最短时间。

    【输入输出样例1】

    rabbit.in

    rabbit.out

    5 5 2

    1 2

    2 3

    1 4

    1 5

    4 5

    1

    见选手目录下的rabbit / rabbit1.in与rabbit / rabbit1.out

    【输入输出样例1说明】

    在第2和第5兔子窝建造避难所,这样其它兔子窝的兔子最多只需要经过1路径就可以到达某个避难所。

    【输入输出样例2】

    见选手目录下的rabbit / rabbit2.in与rabbit / rabbit2.out

    【数据规模与约定】

    对于30%数据,N≤15K≤4;

    对于60%数据,N≤100;

    对于100%的数据,1≤K≤N≤1,0001≤M≤1,500

    一遇到这类题就很晕

    思路:

      有一个点入度大于二,这是一个突破点。我只要把这个点的避难所找到,剩下的就是链或者是环了。

      但是即使是即使给我一堆链和环,也无法直接找出最后一只到达避难所的兔子花费的最短时间,

      所以只能二分一个时间,把问题转化成对于这个时间是否符合题意(不一定最小)的判定性问题。

    做法出来了:二分答案,先处理入度大于2的点,然后处理链和环最少需要多少个避难所。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define maxn 1000010
    #define ll long long
    using namespace std;
    #define INF 0x7ffffff
    int n,m,k;
    int h[1501],nex[3100],to[3100],cnt,du[1501];
    void add(int x,int y)    {to[++cnt]=y;nex[cnt]=h[x];h[x]=cnt;}
    int root,size;
    bool vis[1501][10];//
    
    void dfs(int now,int pre,int dis,int op)
    {
        vis[now][op]=1;size++;
        if(!dis)    return ;
        for(int i=h[now];i;i=nex[i])
        if((to[i]!=pre)&&(!vis[to[i]][op])&&((op!=2)||(!vis[to[i]][1]))) 
            dfs(to[i],now,dis-1,op);
    }
    int main()
    {
        freopen("rabbit.in","r",stdin);
        freopen("rabbit.out","w",stdout); 
        scanf("%d%d%d",&n,&m,&k);
        int a,b;
        while(m--)
        {
            scanf("%d%d",&a,&b);
            add(a,b);add(b,a);
            du[a]++,du[b]++;
        }
        root=1;
        for(int i=1;i<=n;i++)
        if(du[i]>=3)
        {
            root=i;
            break;
        }
        int l=0,r=n,mid,tmp,put;
        while(l<r)
        {
            mid=(l+r)>>1;
            for(int i=1;i<=n;i++)    vis[i][0]=0;
            dfs(root,0,mid,0);
            put=INF;
            for(int i=1;i<=n;i++)
            if(vis[i][0])
            {
                for(int j=1;j<=n;j++) vis[j][1]=vis[j][2]=0;
                
                dfs(i,0,mid,1);
                tmp=1;
                
                for(int j=1;j<=n;j++)
                if((!vis[j][1])&&(!vis[j][2]))
                {
                    size=0;
                    dfs(j,0,INF,2);
                    tmp+=(size-1)/(2*mid+1)+1;
                }
                
                put=min(put,tmp);
            }
            if(put<=k)    r=mid;
            else l=mid+1;
        }
        printf("%d",l);
        return 0;
    } 

    小数据:

     输入:

      4 4 3

      1 2

      2 3

      1 4

      3 4

    输出: 1

      

      

  • 相关阅读:
    reids学习redis的五种基本数据类型
    CentOS下配置Java开发环境安装redis
    CentOS下配置Java开发环境安装Tomcat
    如何去除掉inlineblock元素之间的默认间距
    js按值传递还是按引用传递?
    overflow: hidden用法,不仅仅是隐藏溢出
    关于WinForm中的DataGridView控件显示数据字典的解决方案。
    C#中对Winform中的DataGridView的控制技巧。(单独控制某单元格的按钮不显示、某单元格的ReadOnly)
    改进版网页表格的合并单元格(支持不连续的列合并)
    [共享]MT随机算法(符合正态分布的随机算法)
  • 原文地址:https://www.cnblogs.com/CLGYPYJ/p/7535882.html
Copyright © 2020-2023  润新知