首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> C++ 入門

POJ 2653 Pick-up sticks:線段相交判斷與拓撲順序

     編輯:C++ 入門

題目大意

依次放置 n 根木棍(線段),後放的在上層。若木棍與已放置的任意木棍相交或接觸,則該木棍「不在最上層」。求最終處於最上層的木棍編號(按放置順序輸出)。

幾何判斷:線段相交/共線重疊

struct Point { double x, y; };
Point operator-(Point A, Point B) { return {A.x-B.x, A.y-B.y}; }
double Cross(Point A, Point B) { return A.x*B.y - A.y*B.x; }
double Dot(Point A, Point B) { return A.x*B.x + A.y*B.y; }

// 嚴格相交(內部交點)
bool SegInter(Point a1, Point a2, Point b1, Point b2) {
    double c1 = Cross(a2-a1, b1-a1);
    double c2 = Cross(a2-a1, b2-a1);
    double c3 = Cross(b2-b1, a1-b1);
    double c4 = Cross(b2-b1, a2-b1);
    return dcmp(c1)*dcmp(c2) < 0 && dcmp(c3)*dcmp(c4) < 0;
}

// 點在線段上(含端點)
bool OnSegment(Point P, Point A, Point B) {
    return dcmp(Cross(A-P, B-P)) == 0 && dcmp(Dot(P-A, P-B)) <= 0;
}

演算法流程

  1. 讀入所有木棍座標存入陣列 stick[1..n]
  2. 對每根木棍 i(1~n),檢查是否與任意 j > i 相交/接觸
  3. 若無交集,則 i 為最上層木棍,加入結果
  4. 輸出結果列表(格式:Top sticks: a, b, c.)

完整代碼

#include <cstdio>
#include <vector>
#include <cmath>
using namespace std;

const double EPS = 1e-10;
int dcmp(double x) { return fabs(x)0?1:-1); }

struct Point { double x, y; };
struct Stick { Point a, b; };

Point operator-(Point A, Point B) { return {A.x-B.x, A.y-B.y}; }
double Cross(Point A, Point B) { return A.x*B.y - A.y*B.x; }
double Dot(Point A, Point B) { return A.x*B.x + A.y*B.y; }

bool SegInter(Point a1, Point a2, Point b1, Point b2) {
    double c1 = Cross(a2-a1, b1-a1), c2 = Cross(a2-a1, b2-a1);
    double c3 = Cross(b2-b1, a1-b1), c4 = Cross(b2-b1, a2-b1);
    return dcmp(c1)*dcmp(c2)<0 && dcmp(c3)*dcmp(c4)<0;
}
bool OnSegment(Point P, Point A, Point B) {
    return dcmp(Cross(A-P, B-P))==0 && dcmp(Dot(P-A, P-B))<=0;
}

int main() {
    int n;
    while (scanf("%d", &n) == 1 && n) {
        vector s(n+1);
        for (int i = 1; i <= n; i++)
            scanf("%lf%lf%lf%lf", &s[i].a.x, &s[i].a.y, &s[i].b.x, &s[i].b.y);

        vector top;
        for (int i = 1; i <= n; i++) {
            bool covered = false;
            for (int j = i+1; j <= n; j++) {
                if (SegInter(s[i].a, s[i].b, s[j].a, s[j].b) ||
                    OnSegment(s[i].a, s[j].a, s[j].b) ||
                    OnSegment(s[i].b, s[j].a, s[j].b)) {
                    covered = true; break;
                }
            }
            if (!covered) top.push_back(i);
        }

        printf("Top sticks: ");
        for (int i = 0; i < top.size(); i++) {
            if (i) printf(", ");
            printf("%d", top[i]);
        }
        printf(".\n");
    }
    return 0;
}

複雜度與優化

  • 暴力 O(n²),n ≤ 1000 可接受(約 50 萬次檢查)
  • 可用掃描線或空間分割優化至 O(n log n),但本題不必要

關鍵點

  1. 相交定義:含端點接觸、共線重疊,均視為「被覆蓋」
  2. 浮點精度:EPS=1e-10,所有比較用 dcmp
  3. 輸出格式:逗號空格分隔,句點結尾
  4. 多測試案例:n=0 結束
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved