A: POJ 2318 TOYS
题意:给一个矩形,给出多个木板的位置(线段),将矩形分割成了多个格子(不一定规则),给出多个toy的位置(抽象成点了),判断每个玩具在第几个格子里。
思路:由于给出的木板是不相交,而且严格从左到右的,所以二分查找toy掉落的位置。判断在哪个区间用叉积判断即可。
代码:
#include<cmath>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
struct Point{
int x,y;
}toys[5005];
struct V{
Point a,b;
}bin[5005];
double crossProduct(V v1,V v2){
double ans = 0;
ans = (v1.b.x-v1.a.x)*(v2.b.y-v2.a.y) - (v1.b.y-v1.a.y)*(v2.b.x-v2.a.x);
return ans;
}
int num[5005],n,m;
int bin_search(Point x){
int l = 0,r = n-1,mid = 0;
V v1;
v1.a = bin[0].a; v1.b = x;
if(crossProduct(v1,bin[0]) < 0)return 0;
v1.a = bin[n-1].a; v1.b = x;
if(crossProduct(v1,bin[n-1]) > 0)return n;
mid = (l+r)/2;
while(l < r){
v1.a = bin[mid].a;
if(crossProduct(v1,bin[mid]) > 0)l = mid+1;
else r = mid;
mid = (l+r)/2;
}
return mid;
}
int main(){
int x1,y1,x2,y2,xx1,xx2,x,y;
while(cin>>n,n){
cin>>m>>x1>>y1>>x2>>y2;
for (int i = 0; i < n; i++)
{
cin>>xx1>>xx2;
bin[i].b.x = xx1;bin[i].b.y = y1;
bin[i].a.x = xx2;bin[i].a.y = y2;
}
memset(num,0,sizeof(num));
Point t;
for (int j = 0; j < m; j++)
{
cin>>x>>y;
t.x = x;
t.y = y;
num[bin_search(t)]++;
}
for (int i = 0; i <= n; i++)
{
printf("%d: %d\n",i,num[i]);
}
printf("\n");
}
return 0;
}
B: POJ 2398 Toy Storage
题意:和上题一样,只是木板的放置位置并没有严格排序,要求输出的结果是x: y,表示一共有y块里面有x个玩具的模块。输出按x的升序输出。
思路:将木板排序后,同上题。
代码:
#include<cmath>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
struct Point{
int x,y;
}toys[5005];
struct V{
Point a,b;
}bin[5005];
double crossProduct(V v1,V v2){
double ans = 0;
ans = (v1.b.x-v1.a.x)*(v2.b.y-v2.a.y) - (v1.b.y-v1.a.y)*(v2.b.x-v2.a.x);
return ans;
}
int num[5005],n,m;
int bin_search(Point x){
int l = 0,r = n-1,mid = 0;
V v1;
v1.a = bin[0].a; v1.b = x;
if(crossProduct(v1,bin[0]) < 0)return 0;
v1.a = bin[n-1].a; v1.b = x;
if(crossProduct(v1,bin[n-1]) > 0)return n;
mid = (l+r)/2;
while(l < r){
v1.a = bin[mid].a;
if(crossProduct(v1,bin[mid]) > 0)l = mid+1;
else r = mid;
mid = (l+r)/2;
}
return mid;
}
int cmp(V a,V b){
return a.a.x < b.a.x;
}
int main(){
int x1,y1,x2,y2,xx1,xx2,x,y;
while(cin>>n,n){
cin>>m>>x1>>y1>>x2>>y2;
for (int i = 0; i < n; i++)
{
cin>>xx1>>xx2;
bin[i].b.x = xx1;bin[i].b.y = y1;
bin[i].a.x = xx2;bin[i].a.y = y2;
}
sort(bin,bin+n,cmp);
memset(num,0,sizeof(num));
Point t;
for (int j = 0; j < m; j++)
{
cin>>x>>y;
t.x = x;
t.y = y;
num[bin_search(t)]++;
}
int num2[1005];
memset(num2,0,sizeof(num2));
for (int i = 0; i <= n; i++)
{
if(num[i] != 0)num2[num[i]]++;
}
printf("Box\n");
for (int i = 1; i <= m; i++)
{
if(num2[i] != 0){
printf("%d: %d\n",i,num2[i]);
}
}
}
return 0;
}
题意:给出n条线段,问能否找一个角度,使所有线段以该角度投影到一条直线上,使得所有的线段的投影都有公共点。
思路:将原题题意 理解 变换为 能否找到一条直线 与所有线段都有交点。数据大小只有100,随意枚举O(n^3)完全可以。
注意:用两点确定一条直线时,保证这两点不相等。判断直线和线段的交点,用线段两端点和直线上两点做两次叉积求乘积,为负即为相交。
代码:
#include<cmath>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
#define eps 1e-8
struct Point{
double x,y;
}toys[5005];
struct V{
Point a,b;
}bin[5005];
struct Seg{
Point a,b;
}s[110];
int n;
double crossProduct(V v1,V v2){//v1 X v2
double ans = 0;
ans = (v1.b.x-v1.a.x)*(v2.b.y-v2.a.y) - (v1.b.y-v1.a.y)*(v2.b.x-v2.a.x);
return ans;
}
double cross(Point a,Point b,Point c){//b->a X b->c
return (a.x-b.x)*(c.y-b.y)-(c.x-b.x)*(a.y-b.y);
}
bool ok(Point a,Point b){
if(fabs(a.x-b.x)<eps && fabs(a.y-b.y)<eps)return 0;
for (int i = 0; i < n; i++)
{
if(cross(a,s[i].a,b) * cross(a,s[i].b,b) > 0)
return false;
}
return true;
}
int main(){
int t;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for (int i = 0; i < n; i++)
scanf("%lf%lf%lf%lf",&s[i].a.x,&s[i].a.y,&s[i].b.x,&s[i].b.y);
if(n == 1){puts("Yes!");continue;};
bool flag = false;
for (int i = 0; i < n && !flag; i++)
for (int j = i+1; j < n && !flag; j++){
if(ok(s[i].a,s[j].a)||ok(s[i].a,s[j].b)||ok(s[i].b,s[j].a)||ok(s[i].b,s[j].b))
flag = true;
}
puts(flag?"Yes!":"No!");
}
return 0;
}
D:POJ 1296 Intersecting Lines
题意:判断两条直线的关系:平行,重合,交于一点(输出交点)
思路:叉积判断是否平行或重合,否则数学方法求直线交点。
注意:G++用%.2lf会WA,换c++就好了。(只限POJ)
代码:
#include<cmath>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
#define eps 1e-6
struct Point{double x,y;};
struct Line{Point a,b;};
double cross(Point a,Point b,Point c){//b->a X b->c
return (a.x-b.x)*(c.y-b.y)-(c.x-b.x)*(a.y-b.y);
}
double crossProduct(Line v1,Line v2){
return (v1.b.x-v1.a.x)*(v2.b.y-v2.a.y) - (v1.b.y-v1.a.y)*(v2.b.x-v2.a.x);
}
inline bool equal(double x,double y){
if(fabs(x-y)<eps)return true;
return false;
}
int n;
int main(){
while(~scanf("%d",&n)){
printf("INTERSECTING LINES OUTPUT\n");
Line l1,l2;
while(n--){
scanf("%lf%lf%lf%lf",&l1.a.x,&l1.a.y,&l1.b.x,&l1.b.y);
scanf("%lf%lf%lf%lf",&l2.a.x,&l2.a.y,&l2.b.x,&l2.b.y);
if(fabs(crossProduct(l1,l2)) < eps){
Line l3; l3.a = l1.a;
/*新建一条直线(从l1的一点指向l2的一点)用于判断两直线是否重合。*/
/*但需要注意选的两个点不能重合。。。*/
if(equal(l1.a.x,l2.b.x) && equal(l1.a.y,l2.b.y))l3.b = l2.a;
else l3.b = l2.b;
if(fabs(crossProduct(l1,l3)) < eps)
puts("LINE");
else puts("NONE");
}else{
Point ans;
bool c1 = equal(l1.a.x,l1.b.x),c2 = equal(l2.a.x,l2.b.x);
double k1,k2,b1,b2;
if(c1 && !c2){
k2 = (l2.b.y-l2.a.y)/(l2.b.x-l2.a.x);
b2 = l2.b.y-k2*l2.b.x;
ans.x = l1.a.x;
ans.y = k2*ans.x+b2;
}else if(!c1 && c2){
k1 = (l1.b.y-l1.a.y)/(l1.b.x-l1.a.x);
b1 = l1.b.y-k1*l1.b.x;
ans.x = l2.a.x;
ans.y = k1*ans.x+b1;
}else if(!c1 && !c2){
k2 = (l2.b.y-l2.a.y)/(l2.b.x-l2.a.x);
b2 = l2.b.y-k2*l2.b.x;
k1 = (l1.b.y-l1.a.y)/(l1.b.x-l1.a.x);
b1 = l1.b.y-k1*l1.b.x;
ans.x = (b1-b2)/(k2-k1);
ans.y = k1*ans.x+b1;
}
printf("POINT %.2lf %.2lf\n",ans.x,ans.y);
}
}
printf("END OF OUTPUT\n");
}
return 0;
}