利用二分法求解
扫描二维码
随时随地手机看文章
题意:
一个农夫带着k头牛去住店,(人一间,每牛一间)已知该旅店共有n间房,其中部分房间已有人住,房间住宿情况由01串表示,0表示空,1表示已有人住,剩余房间足够容纳(k+1)头牛/人。为了保障牛的安全,希望人住的房间离最远的牛的房间位置尽量小,输出最小距离。
思路:
很明显为了让人住的离最远的牛最近,那么最后这批人牛住的房间肯定是连续的(不算原有的住宿人员),且人住的位置离中心点越近越好。首先,枚举住宿的左区间,如果左端点已有人住,则跳过该点,如果空,则二分以该点为左端点,空闲房间数为k+1的最左位置。随后在这个区间内,开始寻找空闲的最中心位置(距离远的那端尽量小),利用区间长度奇偶性设置两个指针p1,p2的初始位置,随后分别往两端移动,因为一定有空闲位置,且两指针同时移动,不会出现越界情况。最后找到一个解,则计算最远距离,若小于最优值,则更新。
代码:
#include#include#include#includeusing namespace std; char s[100010]; int room[100010]; int main() { int n,k,len,le,ri,border,ans,pos; //读入 scanf("%d%d",&n,&k); scanf("%s",s); room[0]=0; for(int i=1;i<=n;i++) { //前缀和 if(s[i-1]-'0') room[i]=room[i-1]; else room[i]=room[i-1]+1; } //设置一个肯定会被更新的最大值 ans=10e6; for(int i=1;i<=n;i++) { //该点已有人住 if(room[i]==room[i-1]) continue; le=i; ri=n; border=-1; //二分右区间 while(le>1; if(room[mid]-room[i-1]>k) { border=mid; ri=mid-1; } else le=mid+1; } //如果能找到k+1个房间 if(border!=-1) { int len=(border-i),p1,p2; //根据区间长度奇偶性,设置p1,p2 if(len%2) { p1=(border+i)>>1; p2=(border+i)/2+1; } else { p1=p2=(border+i)>>1; } //寻找最先出现空闲房间 while(1) { if((room[p1]!=room[p1-1])) { pos=p1; break; } else if(room[p2]!=room[p2-1]) { pos=p2; break; } p1--; p2++; } //更新最优值 ans=min(ans,max(pos-i,border-pos)); } //说明剩下,已无可能有k+1个房间 else break; } printf("%dn",ans); return 0; }