【备战秋招】每日一题:2023.03.26-腾讯笔试题(第五题)-割钢板

本文描述了一位锻造家如何利用算法规划斜率为±1的切割线,以最大化从大矩形钢板中获得小钢板的数量,涉及到坐标系、交点计算和几何形状分析。
摘要由CSDN通过智能技术生成

为了更好的阅读体检,可以查看我的算法学习网
在线评测链接:P1132

题目内容

塔子哥是一位著名的锻造家,他经常需要切割钢板来制作各种家具和工艺品。今天,他拿到了一块非常大的矩形钢板,需要将其切割成多个小钢板来制作家具。

为了使得切割后的小钢板能够充分利用,塔子哥需要仔细地规划每一条切割线的位置。他希望每条切割线都是斜着的,因为这样可以得到更多的小钢板。同时,他也想要确保钢板的美观程度,所以每条切割线的斜率只能是 − 1 -1 1 1 1 1

为了更好地规划切割线的位置,塔子哥先将钢板放到笛卡尔坐标系中,左下角的坐标为 ( 0 , 0 ) (0,0) (0,0),左上角的坐标为 ( 0 , H ) (0,H) (0,H),右下角的坐标为 ( W , 0 ) (W,0) (W,0),右上角的坐标为 ( W , H ) (W,H) (W,H)。然后,他画了 m m m 条标记线,并将每条标记线的位置表示为两个整数坐标点 ( x i , 1 , y i , 1 ) (x_{i,1},y_{i,1}) (xi,1,yi,1) ( x i , 2 , y i , 2 ) (x_{i,2},y_{i,2}) (xi,2,yi,2),这样他就可以用锯子沿着每条标记线进行切割。

现在,塔子哥想知道,如果按照这些标记线进行切割,会得到多少个小钢板。

输入描述

第一行输入两个正整数 H H H W W W 表示钢板的高度和长度

第二行输入一个正整数 m m m 表示标记线的条数。

接下来 m m m 行每行四个正整数 x i , 1 , y i , 1 , x i , 2 , y i , 2 x_{i,1},y_{i,1}, x_{i,2},y_{i,2} xi,1,yi,1,xi,2,yi,2 表示标记线经过的坐标点。( 1 ≤ H , W ≤ 500 , 1 ≤ m ≤ 1 0 3 , 0 ≤ x i , 1 , x i , 2 ≤ W , 0 ≤ y i , 1 , y i , 2 ≤ H 1\le H,W \le 500,1\le m\le 10^3,0 \le x_{i,1},x_{i,2}\le W, 0\le y_{i,1},y_{i,2} \le H 1H,W500,1m103,0xi,1,xi,2W,0yi,1,yi,2H

数据保证 ( x i , 1 , y i , 1 ) ≠ ( x i , 2 , y i , 2 ) (x_{i,1},y_{i,1}) \neq (x_{i,2},y_{i,2}) (xi,1,yi,1)=(xi,2,yi,2)

注:如果某条线段出现了多次,按照一次统计即可。

输出描述

输出小钢板的个数。

样例

样例一

输入

1 3
1
1 1 0 1

输出

2

样例二

输入

2 3
2
0 1 0 1
1 0 1 0

输出

3

题目思路

首先将斜率为1和-1的直线分开,由于给出的两点一定在矩形内,所以该直线一定与矩形相交。首先将斜率为-1(或1)的直线先切到矩形上,那么会将矩形分成斜率为-1(或1)的直线条数加一。再将斜率为1(或-1)的直线加入进来,无论与其他直线有没有交点都会产生一个新的矩形。如果该直线与已有的-1(或1)的直线的交点在矩形外,那么将不产生新得矩形,如果交点在矩形内部那么就会产生一个新的矩形。

代码

#include<bits/stdc++.h>

using namespace std;

const int M = 1e3 + 5;
const double eps = 1e-8;

int sgn(double x){
    if(fabs(x) < eps)return 0;
    if(x < 0)return -1;
    else return 1;
}

struct Point{
    double x, y;

    void input(){
        scanf("%lf%lf",&x,&y);
    }
    Point(){}
    Point(double _x, double _y){
        x = _x, y = _y;
    }

    double operator^ (const Point &b)const{
        return x * b.y - y * b.x;
    }

    double operator* (const Point &b)const{
        return x * b.x + y * b.y;
    }

    Point operator -(const Point &b)const{
        return Point(x-b.x,y-b.y);
    }
};

struct Line {
    Point s, e;

    void input(){
        s.input();
        e.input();
    }

    Point crosspoint(Line v){
        double a1 = (v.e - v.s)^(s - v.s);
        double a2 = (v.e - v.s)^(e - v.s);
        return Point((s.x * a2 - e.x * a1) / (a2 - a1), (s.y * a2 - e.y * a1) / (a2 - a1));
    }//求两直线交点

    bool isone() {
        return (e.y - s.y) / (e.x - s.x) > 0;
    }//判断斜率是1还是-1,1为true,-1为false
};


int h, w;

void solve() {
    cin >> h >> w;
    int m;
    cin >> m;
    vector<Line> v1, v2;//v1存斜率为1的直线,v2存斜率为-1的直线
    Line l;
    for (int i = 1; i <= m; i++) {
        l.input();
        if (l.isone()) v1.push_back(l);
        else v2.push_back(l);
    }
    int ans = v1.size() + 1;//初始化为斜率为1的直线的个数加一
    for (int i = 0; i < v2.size(); i++) {
        int cnt = 1;//必会产生新矩形
        for (int j = 0; j < v1.size(); j++) {
            Point p = v2[i].crosspoint(v1[j]);
            if (p.x < w && p.x > 0 && p.y < h && p.y > 0) {//判断交点是否在矩形内,记录这类交点个数
                cnt++;
            }
        }
        ans += cnt;
    }
    cout << ans << endl;
}

int main() {
    int t = 1;
    // cin >> t;
    while (t--) solve();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

塔子哥学算法

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值