其他分享
首页 > 其他分享> > 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内没有的数字就会产生偏差

 

标签:二分,入圈,int,sum,mid,121,枚举,alls,赶牛
来源: https://www.cnblogs.com/ndfwblog/p/14169586.html