1. 程式人生 > 實用技巧 >121. 趕牛入圈 AcWing

121. 趕牛入圈 AcWing

原題連結

錯誤思路:

參考了鐳射炸彈,用變數儲存三葉草的最大座標,列舉左下角時只列舉到最大座標處,結合二分求最小邊長,但我的二分完全寫錯了,我寫的二分是如果Mid不是最小的邊長,則返回False,但實際上二分的check函式是檢查答案的合理性(即這個mid邊長下,是否存在正方形至少含C面積三葉草)

糾正思路:

xy座標的範圍在1~10000,而實際上只有500個要用,因此可以想到離散化,並且這道題答案顯然具有單調性,二分法是必定的.這道題離散化座標實際上是壓縮了矩陣,將沒有三葉草的地方都刪去,但是這樣二分距離就不是簡單地列舉i+mid,j+mid.

 1 #include <bits/stdc++.h>
 2
using namespace std; 3 const int N = 10010; 4 int sum[N][N],n,c; 5 typedef pair<int,int> pii; 6 pii p[N]; 7 vector<int> alls; 8 /* 9 一.二分答案:二分邊長,如果面積內>=c,則為合格解(二分,首先找合格解) 10 二.N範圍是10000,暴力列舉正方形的某個點一定超時, 但是實際的n<500,可以考慮離散化 11 */ 12 int Get_id(int x) 13 { 14 return lower_bound(alls.begin(),alls.end(),x)-alls.begin();
15 } 16 bool check(int mid){ 17 for(int i=1,x=0;i<alls.size();i++){ 18 while(alls[i]-alls[x+1]+1>mid) x++; 19 for(int j=1,y=0;j<alls.size();j++){ 20 while(alls[j]-alls[y+1]+1>mid) y++; 21 int s = sum[i][j]-sum[i][y]-sum[x][j]+sum[x][y]; 22 if
(s>=c) return true; 23 } 24 } 25 return false; 26 } 27 int main() 28 { 29 scanf("%d%d",&c,&n); 30 alls.push_back(0); 31 for(int i=1;i<=n;i++) { 32 scanf("%d%d",&p[i].first,&p[i].second); 33 alls.push_back(p[i].first); alls.push_back(p[i].second); 34 } 35 sort(alls.begin(),alls.end()); 36 alls.erase(unique(alls.begin(),alls.end()),alls.end()); 37 for(int i=1;i<=n;i++) { 38 sum[Get_id(p[i].first)][Get_id(p[i].second)]++; 39 //printf("%d %d\n",Get_id(p[i].first),Get_id(p[i].second)); 40 } 41 for(int i=1;i<alls.size();i++) 42 for(int j=1;j<alls.size();j++) 43 sum[i][j]+=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]; 44 int low = 1; int high = 1e4; 45 while(low<high){ 46 int mid = low+high>>1; 47 if(check(mid)) high = mid; 48 else low = mid+1; 49 } 50 printf("%d\n",low); 51 }

注意:


我們計算的字首和是經過壓縮的字首和,i與j的距離不是1而是要帶入alls的下標才能計算,這樣check出的mid才是真正的距離,如果我們採用以下方案計算:

 1 bool check(int mid){//這樣返回的是壓縮後的mid的邊長 
 2     for(int i=1;i<alls.size();i++){//y總的做法返回的就是壓縮前的邊長 
 3         //while(alls[i]-alls[x+1]+1>mid) x++;//移動到最後一個與(i,j)距離>mid的點
 4         int x =  Get_id(alls[i]+mid-1);
 5         for(int j=1;j<alls.size();j++){
 6             while(alls[j]-alls[y+1]+1>mid) y++;???為什麼 
 7             int y = Get_id(alls[j]+mid-1);//壓縮前實際要+3,壓縮後只要+1 
 8         //    printf("%d %d\n",x,y);
 9             int s = sum[x][y]-sum[i-1][y]-sum[x][j-1]+sum[i-1][j-1];
10             if(s>=c) return true; 
11         }
12     }
13     return false;
14 }
錯誤思路

x返回的是alls[i]加上多少後,才能得到與(i,j)形成符合條件的正方形的數字,例如alls[i]=1,如果形成符合條件的正方形最少加上2,因為lower_bound返回>=的數字,這樣就會導致答案錯誤,正解就是列舉座標,看哪個下標會與(i,j)相差mid且符合條件(上面的正確程式碼基本默寫y總的思路),如果代入alls內沒有的數字就會產生偏差