【问题描述】
在一片草原上有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≤15,K≤4;
对于60%的数据,N≤100;
对于100%的数据,1≤K≤N≤1,000,1≤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