叉积+二分
如果toys在当前板的左边 cross(L,toys,U) < 0
反之在右边会 > 0
根据这个,我们进行二分;
为什么最后得到的不是mid而是l呢?
我们来看这张图.
加入现在是 l = 2 , r = 5;mid = 3; toy在4纸板右边,5纸板左边,
执行l = l +1 = 3, r = 5, mid = 4;依然>0 执行,
l = l + 1 = 4,r = 5, mid = 4; 依然大于0 ,执行
l = l + 1 = 5, r= 5, 退出; 此时l = 5, 之前toy确实在l右边,可是现在在它左边了.(有的情况还是会在右边)
所以我们后面要加一个判断:
if(cross(CardB[r].L, Toys, CardB[r].U) < 0) N_Toys[l]++; else N_Toys[l+1]++;
显然,我们同样可以:
if(cross(CardB[r].L, Toys, CardB[r].U) > 0) N_Toys[r+1]++; else N_Toys[r]++;
那么,如果利用mid 改怎么改写代码呢?
for(int i = 0; i < m; i++) { l = 0, r = n-1; scanf("%d%d",&Toys.x,&Toys.y); while(l <= r) { mid = (l + r) >> 1; if(cross(CardB[mid].L, Toys, CardB[mid].U) > 0) l = mid + 1; else r = mid - 1; } if(cross(CardB[mid].L, Toys, CardB[mid].U) > 0) N_Toys[mid+1]++; else N_Toys[mid]++; }
/* *POJ 2318 *fuqiang *几何初步 *2013/8/2 */ #include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <algorithm> using namespace std; const int maxn = 5000+3; const double PI = 4.0*atan(1.0); const double eps = 1e-8; struct point { int x; int y; } Toys; struct Line { point U; point L; } CardB[maxn]; int N_Toys[maxn]; int cross(const point &p0, const point &p1, const point &p2) //计算叉积 { return (p1.x-p0.x)*(p2.y-p0.y) - (p2.x-p0.x)*(p1.y-p0.y); } int main() { #ifndef ONLINE_JUDGE freopen("in","r",stdin); #endif int n,m,x1,y1,x2,y2; while(scanf("%d",&n) && n) { scanf("%d%d%d%d%d",&m,&x1,&y1,&x2,&y2); for(int i = 0; i < n; i++) { scanf("%d%d", &CardB[i].U.x, &CardB[i].L.x); CardB[i].U.y = y1; CardB[i].L.y = y2; } memset(N_Toys,0,sizeof(N_Toys)); int l, r, mid, ans, p; for(int i = 0; i < m; i++) { l = 0, r = n-1; scanf("%d%d",&Toys.x,&Toys.y); while(l < r) { mid = (l + r) >> 1; if(cross(CardB[mid].L, Toys, CardB[mid].U) > 0) l = mid + 1; else r = mid; } if(cross(CardB[r].L, Toys, CardB[r].U) < 0) N_Toys[l]++; else N_Toys[l+1]++; } for(int i = 0; i <= n; i++) { printf("%d: %d\n",i,N_Toys[i]); } printf("\n"); } }
还有个更好的点子,别人的代码:
将最后一个点也作为纸板,此时 我们只需要返回l:
while (l <= r) { mid = (l + r) >> 1; if ( cal (low[mid], high[mid], cc) > 0 ) l = mid + 1; else r = mid - 1; } return l; }
POJ 2398
加个排序,统计后输出,注意t>0
/* *POJ 2318 *fuqiang *几何初步 *2013/8/2 */ #include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <algorithm> using namespace std; const int maxn = 5000+3; const double PI = 4.0*atan(1.0); const double eps = 1e-8; struct point { int x; int y; } Toys; struct Line { point U; point L; } CardB[maxn]; int N_Toys[maxn]; int cross(const point &p0, const point &p1, const point &p2) //计算叉积 { return (p1.x-p0.x)*(p2.y-p0.y) - (p2.x-p0.x)*(p1.y-p0.y); } int cmp(Line a, Line b)//sort... { return a.L.x < b.L.x; } int main() { #ifndef ONLINE_JUDGE freopen("in","r",stdin); #endif int n,m,x1,y1,x2,y2; while(scanf("%d",&n) && n) { scanf("%d%d%d%d%d",&m,&x1,&y1,&x2,&y2); for(int i = 0; i < n; i++) { scanf("%d%d", &CardB[i].U.x, &CardB[i].L.x); CardB[i].U.y = y1; CardB[i].L.y = y2; } sort(CardB,CardB+n,cmp); //sort memset(N_Toys,0,sizeof(N_Toys)); int l, r, mid, ans, p; for(int i = 0; i < m; i++) { l = 0, r = n-1; scanf("%d%d",&Toys.x,&Toys.y); while(l <= r) { mid = (l + r) >> 1; if(cross(CardB[mid].L, Toys, CardB[mid].U) > 0) l = mid + 1; else r = mid - 1; } if(cross(CardB[mid].L, Toys, CardB[mid].U) > 0) N_Toys[mid+1]++; else N_Toys[mid]++; } sort(N_Toys,N_Toys+n+1); printf("Box\n"); int st = 0; while(N_Toys[st] == 0) st++; for(int i = st; i <= n; ) { int num = 1; printf("%d: ",N_Toys[i]); for(int j = i++; j <= n; j++,i++) { if(N_Toys[i]==N_Toys[j]) num++; else break; } printf("%d\n",num); } // printf("\n"); } }