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

  

  

posted @   浪矢-CL  阅读(322)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App
点击右上角即可分享
微信分享提示