hdu 2150- Pipe-解析幾何

kewlgrl發表於2016-03-09

Pipe

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1968    Accepted Submission(s): 768


Problem Description
經過激烈的爭奪,Lele終於把那塊地從Yueyue的手裡搶了回來。接下來,Lele要開始建造他的灌溉系統。

通過諮詢Lele的好友——化學系的TT,Lele決定在田裡挖出N條溝渠,每條溝渠輸送一種肥料。

每條溝渠可以看作是一條折線,也就是一系列線段首尾連線而成(除了第一條線段開頭和最後一條線段的結尾)。由於溝渠很細,你可以忽略掉它的寬度。

由於不同的肥料之間混合會發生化學反應,所以修建的溝渠與溝渠之間不能相交。

現在TT給Lele畫了一些設計圖,Lele請你判斷一下設計圖中的溝渠與溝渠之間是否有相交。
 

Input
本題目包含多組測試,請處理到檔案結束(EOF)。
每組測試的第一行有一個正整數N(0<N<30),表示管道的數目。接下來給出這N條管道的資訊。
對於每條管道,第一行是一個正整數K(0<K<100),表示這條管道是由K個端點組成。
接下來的K行給出這K個端點資訊。每個端點佔一行,用兩個整數X和Y(0<X,Y<1000)分別表示這個端點的橫座標和縱座標的值。
 

Output
對於每組測試,如果該測試管道與管道之間有相交的話,輸出"Yes",否則輸出"No"。

 

Sample Input
2 2 0 0 1 1 2 0 1 1 0 2 2 0 0 1 1 2 1 0 2 1 2 3 0 0 1 1 2 1 2 2 0 3 0
 

Sample Output
Yes No No
 

Author
Linle
 

Source
 

Recommend
lcy   |   We have carefully selected several similar problems for you:  1392 1115 2108 1086 2036 

題意:
題目的意思是給定線段的兩個端點的座標,判斷同一組的幾條線段是否相交,是就yes,不是就no。

知識點:
我們分兩步確定兩條線段是否相交:
(1)快速排斥試驗
設以線段 P1P2 為對角線的矩形為R, 設以線段 Q1Q2 為對角線的矩形為T,
如果R和T不相交,顯然兩線段不會相交。
(2)跨立試驗
如果兩線段相交,則兩線段必然相互跨立對方。
若P1P2跨立Q1Q2 ,則向量 ( P1 - Q1 ) 和( P2 - Q1 )位於向量( Q2 - Q1 ) 的兩側,
即( P1 - Q1 ) × ( Q2 - Q1 ) * ( P2 - Q1 ) × ( Q2 - Q1 ) < 0。
上式可改寫成( P1 - Q1 ) × ( Q2 - Q1 ) * ( Q2 - Q1 ) × ( P2 - Q1 ) > 0。
當 ( P1 - Q1 ) × ( Q2 - Q1 ) = 0 時,說明 ( P1 - Q1 ) 和 ( Q2 - Q1 )共線,
但是因為已經通過快速排斥試驗,所以 P1 一定線上段 Q1Q2上;
同理,( Q2 - Q1 ) ×(P2 - Q1 ) = 0 說明 P2 一定線上段 Q1Q2上。
所以判斷P1P2跨立Q1Q2的依據是:( P1 - Q1 ) × ( Q2 - Q1 ) * ( Q2 - Q1 ) × ( P2 - Q1 ) >= 0。
同理判斷Q1Q2跨立P1P2的依據是:( Q1 - P1 ) × ( P2 - P1 ) * ( P2 - P1 ) × ( Q2 - P1 ) >= 0。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
#define MAX 100+5
typedef long long LL;
const double pi=3.141592653589793;
const int INF=1e9;
const double inf=1e20;
const double eps=1e-6;
const int mod=1000000007;
struct point
{
    int x,y;
} p[35][105];
double circulation(point a,point b,point c)///計算向量BA、CA的叉積
{
    return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
}
bool cross(point a,point b,point c,point d)///判斷線段AB和CD是否相交
{
    if(max(a.x,b.x)>=min(c.x,d.x)&&///快速排斥試驗
            max(c.x,d.x)>=min(a.x,b.x)&&
            max(a.y,b.y)>=min(c.y,d.y)&&
            max(c.y,d.y)>=min(a.y,b.y)&&
            circulation(a,b,c)*circulation(a,d,b)>=0&&///跨立試驗
            circulation(c,a,d)*circulation(c,d,b)>=0)
        return true;
    return false;
}
int main()
{
    int n,k[35];
    while(cin>>n)///n表示管道的數目
    {
        memset(k,0,sizeof(k));
        memset(p,0,sizeof(p));
        for(int i=0; i<n; i++)
        {
            cin>>k[i];///i表示是第i條管道,k[i]表示這條管道是由k[i]個端點組成
            for(int j=0; j<k[i]; j++)
                scanf("%d%d",&p[i][j].x,&p[i][j].y);
        }
        if(n==1)
        {
            printf("No\n");
            continue;
        }
        int flag=0;
        for(int i=0; i<n-1; i++)///列舉每條折線段上的每段線段
                        ///判斷其是否與其它折線段的線段相交
            for(int j=1; j<k[i]; j++)
                for(int t=i+1; t<n; t++)
                    for(int h=1; h<k[t]; h++)
                        if(cross(p[i][j-1],p[i][j],p[t][h-1],p[t][h]))
                        {
                            flag=1;
                            break;
                        }
        if(flag) printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}


相關文章