题目概述
一个正方形,四个端点分别在(0,0),(0,100),(100,0),(100,100),有N条直线与之相交,两个交点坐标(x3,y3),(x2,y2),不存在任何两条重合的直线,正方形内有一定点(X,Y),该点不在任何直线上,也不在正方形边上
输入:
第一行N,其后N行,每行4个整数x3,y3,x2,y2,下一行两个浮点数X,Y
输入只有一组
限制:
0<=N<=30
输出:
一个字符串,记从定点发出的射线与正方形的边和给出的直线在正方形内部或边上最少的交点数为%leastwalls%,则字符串为
Number of doors = %leastwalls%
等号两侧各有一空格,输出只有一组
样例输入:
case1:
7
20 0 37 100
40 0 76 100
85 0 0 75
100 90 0 90
0 71 100 61
0 14 100 38
100 47 47 100
54.5 55.4
case2:
0
case3:
1
10 0 10 100
50 50
样例输出:
case1:
Number of doors = 2
case2:
Number of doors = 1
case3:
Number of doors = 1
讨论:
向量积的应用,原题不是直线,是墙,而且要求只能从每一段的中点处打孔,但是这个条件有无不影响结果,没有写出来
题解状态:
108K,32MS,C++,1820B
题解代码:
#include<string.h>
#include<stdio.h>
#include<iostream>
#include<set>
#include<map>
#include<string>
#include<vector>
#include<math.h>
using namespace std;
#define INF 0x3f3f3f3f
#define maxx(a,b) ((a)>(b)?(a):(b))
#define minn(a,b) ((a)<(b)?(a):(b))
#define MAXN 33
#define memset0(a) memset(a,0,sizeof(a))
const double eps = 1e-10;//浮点误差值,差小于之的两个浮点数视为相等
struct point
{
double x;
double y;
point(double a, double b) :x(a), y(b) {};//poj不能用大括号初始化结构体
};
double x3[MAXN];
double y3[MAXN];//意外的是,y1和y0在math.h中有重名函数,怎么以前没注意到这个问题
double x2[MAXN];
double y2[MAXN];//原始数据,放每条直线的四个坐标值
int N;//直线条数合计
inline bool xproduct(point a, point b, point c, point d)//模版,两直线是否相交
{
if (minn(a.x, b.x) > maxx(c.x, d.x) || minn(a.y, b.y) > maxx(c.y, d.y) || minn(c.x, d.x) > maxx(a.x, b.x) || minn(c.y, d.y) > maxx(a.y, b.y))
return 0;
double h, i, j, k;
h = (b.x - a.x)*(c.y - a.y) - (b.y - a.y)*(c.x - a.x);
i = (b.x - a.x)*(d.y - a.y) - (b.y - a.y)*(d.x - a.x);
j = (d.x - c.x)*(a.y - c.y) - (d.y - c.y)*(a.x - c.x);
k = (d.x - c.x)*(b.y - c.y) - (d.y - c.y)*(b.x - c.x);
return h*i <= eps&&j*k <= eps;
}//模版结束
int fun()
{
for (int p = 0; p < N; p++)
scanf("%lf%lf%lf%lf", &x3[p], &y3[p], &x2[p], &y2[p]);//input
double X, Y;
scanf("%lf%lf", &X, &Y);//input
//input ends here
int leastwalls = INF;//least walls,初始化最少交点数,原题中不是直线,是墙
for (int p = 0; p < N; p++) {
int walls = 0;
for (int o = 0; o < N; o++) {
walls += xproduct(point(x3[p], y3[p]), point(X, Y), point(x3[o], y3[o]), point(x2[o], y2[o]));
}
leastwalls = minn(leastwalls, walls);
}
for (int p = 0; p < N; p++) {
int walls = 0;
for (int o = 0; o < N; o++) {
walls += xproduct(point(x2[p], y2[p]), point(X, Y), point(x3[o], y3[o]), point(x2[o], y2[o]));
}
leastwalls = minn(leastwalls, walls);
}//这一部分思路相当朴素,枚举直线与正方形的每个交点,并假设在其无限接近的旁比有一个使交点数较少的点(使得原交点不会被计入总数),遍历其他所有直线检查射线与多少直线有交点,最后找个数把最小的记下来,直线不多,N^2也不会太慢,另外其实这里可以合并成一个for函数
return (leastwalls == INF ? 1 : leastwalls);//没有任何直线时只和边相交一次,返回1就行
}
int main(void)
{
//freopen("vs_cin.txt", "r", stdin);
//freopen("vs_cout.txt", "w", stdout);
scanf("%d", &N);//input
printf("Number of doors = %d\n", fun());//output
}
EOF