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 @ 2017-09-17 15:58  浪矢-CL  阅读(319)  评论(0编辑  收藏  举报