2011-08-31 23:12:34Morris

c107. Jack Straws

c107. Jack Straws

內容 :

在一張桌子上倒一些吸管,給你這些吸管2端點的座標,請你寫一個程式來回答某2根吸管是否有相連。相連是指2根吸管有直接接觸或經由其他吸管可以連接。

輸入說明 :

輸入的第一列有一個正整數,代表以下有幾組測試資料。第一列與第一組測試資料,以及各組測試資料間均有一空白列。請參考Sample Input。

每組測試資料的第一列有1個正整數n(1 < n < 13),代表吸管的數目。接下來的n列依序代表第1根吸管到第n根吸管,每列有4個正整數x1, y1, x2, y2,代表這根吸管2端點的座標(x1, y1),( x2, y2)。所有的座標值均小於100,且吸管的長度一定大於0。再接下來的數列為此組測試資料的子問題,每列有2個正整數a,b(均介於1到n之間),你必須回答第a根吸管和第b根吸管有無相連。當a=b=0時代表此組測試資料結束。

輸出說明 :

對每一組測試資料,回答其各子問題。若相連請輸出CONNECTED,否則請輸出NOT CONNECTED

各組測試資料間請輸出一空白列。請參考Sample Output。

範例輸入 :

271 6 3 3 4 6 4 9 4 5 6 7 1 4 3 5 3 5 5 5 5 2 6 3 5 4 7 2 1 4 1 6 3 3 6 7 2 3 1 3 0 021 1 1 31 7 1 51 21 10 0

範例輸出 :

CONNECTEDNOT CONNECTEDCONNECTEDCONNECTEDNOT CONNECTEDCONNECTEDNOT CONNECTEDCONNECTED

提示 :

* Luck 貓翻譯

出處 :

ACM 273 (管理:sa072686)



作法 : 數學
對於相交的兩個線段 :

1. 拿一個線段的一端點, 往外拉三條向量, 分別是拉到自己的另外一個端點,
拉到另外一個線段的兩端點, 這兩個向量分別與自己拉出來的向量外積, 這兩個外積值相乘會小於 0,
外積正負可以看出順時針或者是逆時針, 對於 4 個端點都要符合

2. 或者是有某點在另外一個線段上

/**********************************************************************************/
/*  Problem: c107 "Jack Straws" from ACM 273                                      */
/*  Language: C                                                                   */
/*  Result: AC (0ms, 194KB) on ZeroJudge                                          */
/*  Author: morris1028 at 2011-08-31 23:02:26                                     */
/**********************************************************************************/


#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MaxV 1000000
typedef struct {
    int x, y;
}Point;
typedef struct {
    Point s, e;
}Segment;
Segment D[14];
int Map[14][14];
int Min(int x, int y) {
    return x < y ? x : y;
}
int Max(int x, int y) {
    return x > y ? x : y;
}
int Cross(Point s, Point t1, Point t2, Point e) {
    Point T1, T2, M;
    M.x = e.x-s.x, M.y = e.y-s.y;
    T1.x = t1.x-s.x, T1.y = t1.y-s.y;
    T2.x = t2.x-s.x, T2.y = t2.y-s.y;
    return (M.x*T1.y - M.y*T1.x)*(M.x*T2.y - M.y*T2.x) < 0 ? 1 : 0;
}
int Collinear(Point x, Point y, Point z) {/*x-y-z (O) y-x-Z(X)*/
    int miny = x.y, maxy = x.y;
    miny = Min(x.y, z.y);
    maxy = Max(x.y, z.y);
    if((x.x-y.x)*(z.y-y.y) == (x.y-y.y)*(z.x-y.x) && (x.x <= y.x && z.x >= y.x) &&
        (miny <= y.y && maxy >= y.y))
        return 1;
    return 0;
}
int JudgeIntersect(Segment A, Segment B) {
    if(Cross(A.s, B.s, B.e, A.e) && Cross(A.e, B.s, B.e, A.s) &&
        Cross(B.s, A.s, A.e, B.e) && Cross(B.e, A.s, A.e, B.s))
        return 1;
    if(Collinear(A.s, B.s, A.e) || Collinear(A.s, B.e, A.e) ||
        Collinear(B.s, A.s, B.e) || Collinear(B.s, A.e, B.e) )
        return 1;
    return 0;
}
void Handle(int n) {
    int i, j;
    memset(Map, 0, sizeof(Map));
    for(i = 0; i < n; i++) {
        for(j = 0; j < n; j++) {
            if(JudgeIntersect(D[i], D[j]))
                Map[i][j] = 1;
        }
    }
}
void Floyd(int n) {
    int i, j, k;
    for(i = 0; i < n; ++i)
        for(j = 0; j < n; ++j)
            if(Map[i][j] == 0)
                Map[i][j] = MaxV;
    for(i = 0; i < n; i++)
        for(j = 0; j < n; j++)
            for(k = 0; k < n; k++)
                if(Map[j][i] + Map[i][k] < Map[j][k])
                    Map[j][k] = Map[j][i] + Map[i][k];
}
main() {
    int n, i, j, k, x, y;
    Point T;
    scanf("%d", &k);
    while(k--) {
        scanf("%d", &n);
        for(i = 0; i < n; i++) {
            scanf("%d %d %d %d", &D[i].s.x, &D[i].s.y, &D[i].e.x, &D[i].e.y);
            if(D[i].s.x > D[i].e.x) {
                T = D[i].s, D[i].s = D[i].e, D[i].e = T;
            }
        }
        Handle(n), Floyd(n);
        while(scanf("%d %d", &x, &y) == 2) {
            if(x == 0 && y == 0)    break;
            x--, y--;
            if(Map[x][y] == MaxV)
                puts("NOT CONNECTED");
            else
                puts("CONNECTED");
        }
        if(k)    puts("");
    }
    return 0;
}