poj 1066

题目概述

一个正方形,四个端点分别在(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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值