poj 1092 Farmland

Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 1238 Accepted: 483

Description

We have a map for farming land in a country. The whole farming land of the country is divided into a set of disjoint farming regions. Each farmer owns only one farming region in this country. There is a boundary fence between two neighboring farming regions. The farmland map for this country can be represented in a plane graph. The following Figure-1 shows one example. 
poj <wbr>1092 <wbr>Farmland

Figure-1: Farmland graph G(V,E)

There are two types of edges, boundary edge and non-boundary edge. All edges of G(V,E) except (v8, v6) and (v11, v10) are boundary edges which are between two neighboring farming regions. The "proper farming region" in a Farmland graph is a closed region bounded by a simple cycle and it should not contain any vertices or edges inside. In this figure, the polygon < v1,v9,v8,v7 >is a proper farming region, and the region < v2, v1, v7, v8 , v2, v5, v4, v3 >is not a proper farming region since its boundary cycle is not simple. 
We assume that the farmland graph G(V,E) is a simple connected graph, which does not allow self-loops (Figure-2 (a)) and parallel edges (Figure-2 (b)).Also in Farmland graph G(V,E), we do not consider the outer face of G(V,E).You can see that there are 2 proper farming regions in G(V,E) shown in Figure-1,namely < v1,v9,v8,v7> and < v2,v3,v4,v5>, since there are no vertices or edges inside. But the polygon< v1,v7,v8,v2> is not a proper farming region since vertex v3, v4, and v5 are located in that region. Similarly, the region is not a proper region because a vertex v10 is inside the region.A degenerate polygon < v6, v8> is not a proper region because it has no valid area inside.
poj <wbr>1092 <wbr>Farmland

Figure-2: (a) self-loop < v1,v1> , and (b) 3 parallel edges { < v1,v2>,< v1,v2>, < v1,v2>}

There are other assumptions for input farmland graph data. 
1. There is at least one proper farming region. 
2. The position of each vertex in Farmland graph is distinct. 
3. There is no edge crossing, which means the graph G(V,E) is a plane graph. 
4. Farmland graph G(V,E) is simple and connected. 

Let us define the "size" of proper farming region. The size of proper farming region is the number of boundary edges of that region. For example, the size of the proper farming region < v2,v3,v4,v5 > is 4. 
The problem is to find the number of proper regions that have a specified size.If you are requested to find the number of proper regions with size of 4 in the graph given in Figure-1, you must answer that there are 2 proper regions whose sizes are 4 because farming regions < v1,v9,v8,v7 > and < v2,v3,v4,v5 >are proper regions and their sizes are 4. If there are no such regions, then you have to print 0.

Input

The input consists of M test cases. The first line of the input contains a positive integer M, the number of test cases you are to solve. After the first line,input data for M cases follow. The first line of each test case contains a positive integer N (>=3), the number of vertices. Each of the following N lines is of the form:
i  xi  yi  di  a1  a2  a3  .....  adi

"i" is the vertex number, xi and yi are the coordinate (xi, yi) of the vertex i, and di is the degree of the vertex i. The following { ai } are the adjacent vertices of the vertex i. The last line gives k, the size of proper regions that you have to count. 
Note that M, the number of cases in input is less than 10. N, the number of vertices of a given farmland graph is less than 200. All vertices are located on grid points of the 1000 x 1000 lattice grid.

Output

The output must contain M non-negative integers. Each line contains the answer n to the corresponding case of the input.

Sample Input


2                 
12                   
1  2 6   3  9 7 2 
2  5 6   4  5 3 1 8  
3  3 5   2  4 2      
4  3 4   2  3 5      
5  4 4   2  4 2 
6  7 4   1  8 
7  2 3   2  8 1 
8  5 3   5  7 2 9 12 6 
9  1 2   3  11 8 1 
10 3 2   1  11 
11 2 1   3  10 9 12 
12 6 1   2  8 11 

3                    
1  2 2   2  2 3 
2  1 1   2  1 3 
3  4 1   2  1 2 
4



 

Sample Output


2

0

Source




題目大意:給一個平面圖,找邊數爲k且內部不包含其他點的簡單多邊形的個數。簡單多邊形的定義是多邊形任意兩條不相鄰的邊(包括頂點)不相交不重合。
//============================================================================

算法:枚舉每一條邊做爲起始邊每次找到極角排序後最右邊的邊,重複k次,判斷是否爲符合條件的簡單多邊形,是則計數器加1。

細節很麻煩。。。。

Q:最右邊的邊怎麼定義?
A:首先,將所有邊拆成兩條有向邊。因爲找最右本身就是有方向的提法。
於是當前的邊就有一個指向的點和一個指出的點,我們規定沿着邊的方向找簡單多邊形。

將與指向的點相連且不是指出的點進行極角排序,順序最小的點就是最右的點了。

或者可以這樣理解:將當前邊做爲極軸,正方向取邊的反向。所有與極點相連的邊中極角最小的就是最右邊。



由此易知:每次找最右的邊,最後如果能得到的一個多邊形,則一定是簡單多邊形。



但是還有很多細節。

判斷時候有重邊(比如一個邊數爲3的簡單多邊形會被判斷成6或9之類的)是很好處理的,就是在搜索的時候記錄找過了那些邊和點,在繼續搜索的時候排除這些情況就行了。

還有就是:
1.任意一個合法的簡單多邊形會被判斷成k個符合條件的簡單多邊形。
2.一個合法的簡單多邊形至多隻有一個點有多於兩條邊,那麼會被判斷成兩個。

有向邊的價值在這裏就體現出來了,找到一個簡單多邊形後就可以把構成它的所有有向邊刪掉。
因爲題目保證了圖是平面圖,那麼一條邊至多隻會存在於兩個簡單多邊形上,拆成有向邊後就是一個了。這樣對於第一種情況就可以解決了。
第二種情況在深搜的時候加個特判,是否所有反向邊都已經被刪掉了,如果是,那麼就不計入答案。具體見代碼吧。


CODE

#include

#include

#include

#define eps 1e-7

using namespace std;

bool tmp = 1;

struct Dot

{

    double x, y;

    Dot () {}

    Dot (double x, double y) : x(x), y(y) {}

    Dot operator + (Dot a)

    {

        return Dot (x + a.x, y + a.y);

    }

    Dot operator - (Dot a)

    {

        return Dot (x - a.x, y - a.y);

    }

} d[200];

 

int con[200][15];

bool vis_e[200][15];

bool vis_d[200];

bool insi[200];

int n, len, start;

bool graph[200][200];

bool anti;

 

//con是鄰接表存邊

//vis_evis_d記錄刪掉了哪些邊和點

//graph是鄰接矩陣儲存的邊,方便特判所有方向邊是否都被刪掉

//anti記錄方向邊是否都被刪掉

//len即題目中的kn是點數,start記錄起始點

 

 

double cross (Dot g, Dot h)    //叉積用於找最右邊

{

    return g.x * h.y - g.y * h.x;

}

double mul (Dot g, Dot h)    //點積

{

    return g.x * h.x + g.y * h.y;

}

bool right (Dot g, Dot h, Dot s)    //找最右邊

{

    double ss = cross (g, h);

    double f1 = mul (s, g);

    double f2 = mul (s, h);

    if (ss > eps)

        return 1;

    if (ss < -eps)

        return 0;

    if (f1 < f2)

        return 1;

    return 0;

}

bool dfs (int u, int g, int tmp)    //深搜不停向右

{

    int v = con[u][g];

    insi[v] = 0;

    vis_d[v] = 1;

    anti = anti & graph[v][u];    //判斷方向邊是否都被刪

 

    for (int i=0; i

        if (cross(d[v] - d[u], d[i] - d[u]) > eps)

            insi[i]=0;

//判斷多邊形內是否有點

 

    if (tmp == len)

    {

        if (v != start)

            return 0;

        int flag = 0;

        for (int i = 0; i < n; i++)

            flag = flag | insi[i];    //多邊形內不能有點

        if (!flag)

            vis_e[u][g] = 1,

            graph[u][v] = 1;

        return (flag ^ 1) & (anti ^ 1);    //反向邊

    }

 

    int t = 0;

    for (int i = 0; i < con[v][0]; i++)

    {

        int w = con[v][i+1];

        if (vis_d[w] || vis_e[v][i+1] || w == u)

            continue;

        if (cross (d[u] - d[v], d[w] - d[u]) > -eps

            && (!t || right (d[w] - d[v], d[con[v][t]] - d[v], d[u] - d[v])))

                t = i + 1;

    }

    if (!t)

        return 0;

    int flag = dfs (v, t, tmp + 1);

    if (flag)

        vis_e[u][g] = 1,

        graph[u][v] = 1;

    return flag & (anti ^ 1);

}

int main()

{

    freopen("1.in","r",stdin);

    freopen("1.out","w",stdout);

    int ttt; scanf("%d", &ttt);

    while (ttt--)

    {

        memset(con, 0, sizeof(con));

        scanf("%d", &n);

        for (int i=0; i

        {

            int x;

            scanf("%d", &x);

            x--;

            scanf("%lf %lf", &d[x].x, &d[x].y);

            scanf("%d",&con[x][0]);

            for (int j = 0; j < con[x][0]; j++)

            {

                scanf("%d", &con[x][j+1]);

                con[x][j+1]--;

            }

        }

        scanf("%d", &len);

 

        memset(graph, 0, sizeof (graph));

        memset(vis_e, 0, sizeof (vis_e));

//邊刪掉了就永遠都不會再用了

        int ans = 0;

        for (int i=0; i

            for (int j=0; j

                if (!vis_e[i][j + 1])

                {

                    memset(vis_d, 0, sizeof(vis_d));

                    memset(insi, 1, sizeof(insi));

//點要每次刪除,因爲一個點可能出現在多個簡單多邊形上

 

                    anti = 1;

                    start = i;

                    insi[i] = 0;

                    if (dfs(i, j + 1, 1))

                        ans++;

                }

        printf("%d\n", ans);

    }

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章