1. 程式人生 > >【打CF,學演算法——三星級】CodeForces 645C Enduring Exodus (二分+貪心)

【打CF,學演算法——三星級】CodeForces 645C Enduring Exodus (二分+貪心)

Note

In the first sample, Farmer John can book room 3 for himself, and rooms 1 and 4 for his cows. The distance to the farthest cow is 2. Note that it is impossible to make this distance 1, as there is no block of three consecutive unoccupied rooms.

In the second sample, Farmer John can book room 1 for himself and room 3

for his single cow. The distance between him and his cow is 2.

In the third sample, Farmer John books all three available rooms, taking the middle room for himself so that both cows are next to him. His distance from the farthest cow is 1.

--------------------------------------------------------------------------------------啦啦啦,我是分割線--------------------------------------------------------------------------------------------------------------

題意:

    一個農夫帶著k頭牛去住店,(人一間,每牛一間)已知該旅店共有n間房,其中部分房間已有人住,房間住宿情況由01串表示,0表示空,1表示已有人住,剩餘房間足夠容納(k+1)頭牛/人。為了保障牛的安全,希望人住的房間離最遠的牛的房間位置儘量小,輸出最小距離。

思路:

    很明顯為了讓人住的離最遠的牛最近,那麼最後這批人牛住的房間肯定是連續的(不算原有的住宿人員),且人住的位置離中心點越近越好。首先,列舉住宿的左區間,如果左端點已有人住,則跳過該點,如果空,則二分以該點為左端點,空閒房間數為k+1的最左位置。隨後在這個區間內,開始尋找空閒的最中心位置(距離遠的那端儘量小),利用區間長度奇偶性設定兩個指標p1,p2的初始位置,隨後分別往兩端移動,因為一定有空閒位置,且兩指標同時移動,不會出現越界情況。最後找到一個解,則計算最遠距離,若小於最優值,則更新。

程式碼:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
using 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<=ri)
	   {
		   int mid=(le+ri)>>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("%d\n",ans);
	return 0;
}