poj 1092 Farmland

来源:互联网 发布:创意摆件 知乎 编辑:程序博客网 时间:2024/05/21 09:55
Time Limit: 1000MSMemory Limit: 65536KTotal Submissions: 1238Accepted: 483

Description

We have a map for farming land in a country. Thewhole farming land of the country is divided into a set of disjointfarming regions. Each farmer owns only one farming region in thiscountry. There is a boundary fence between two neighboring farmingregions. The farmland map for this country can be represented in aplane graph. The following Figure-1 shows oneexample. 
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 boundaryedges which are between two neighboring farming regions. The"proper farming region" in a Farmland graph is a closed regionbounded by a simple cycle and it should not contain any vertices oredges inside. In this figure, the polygon < v1,v9,v8,v7 >is aproper farming region, and the region < v2, v1, v7, v8 , v2, v5,v4, v3 >is not a proper farming region since its boundary cycleis not simple. 
We assume that the farmland graph G(V,E) is a simple connectedgraph, which does not allow self-loops (Figure-2 (a)) and paralleledges (Figure-2 (b)).Also in Farmland graph G(V,E), we do notconsider the outer face of G(V,E).You can see that there are 2proper farming regions in G(V,E) shown in Figure-1,namely <v1,v9,v8,v7> and < v2,v3,v4,v5>, since there are novertices or edges inside. But the polygon< v1,v7,v8,v2> isnot a proper farming region since vertex v3, v4, and v5 are locatedin that region. Similarly, the region is not aproper region because a vertex v10 is inside the region.Adegenerate polygon < v6, v8> is not a proper region becauseit has no valid area inside.
poj <wbr>1092 <wbr>Farmland

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

There are other assumptions for input farmland graphdata. 
1. There is at least one proper farmingregion. 
2. The position of each vertex in Farmland graph isdistinct. 
3. There is no edge crossing, which means the graph G(V,E) is aplane graph. 
4. Farmland graph G(V,E) is simple andconnected. 

Let us define the "size" of proper farming region. The size ofproper farming region is the number of boundary edges of thatregion. 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 aspecified size.If you are requested to find the number of properregions with size of 4 in the graph given in Figure-1, you mustanswer that there are 2 proper regions whose sizes are 4 becausefarming regions < v1,v9,v8,v7 > and < v2,v3,v4,v5 >areproper 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 lineof the input contains a positive integer M, the number of testcases you are to solve. After the first line,input data for M casesfollow. The first line of each test case contains a positiveinteger N (>=3), the number of vertices. Each of the following Nlines is of the form:
xi  yi  di  a1 a2  a3  ..... adi

"i" is the vertex number, xi and yi are the coordinate (xi, yi) ofthe 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 givesk, the size of proper regions that you have tocount. 
Note that M, the number of cases in input is less than 10. N, thenumber of vertices of a given farmland graph is less than 200. Allvertices are located on grid points of the 1000 x 1000 latticegrid.

Output

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

Sample Input

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

 

Sample Output

2
0

Source

Taejon 2001



题目大意:给一个平面图,找边数为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) {}

    Dotoperator + (Dot a)

   {

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

   }

    Dotoperator - (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, Doth)   //叉积用于找最右边

{

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

}

double mul (Dot g, Doth)   //点积

{

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

}

bool right (Dot g, Dot h, Dots)   //找最右边

{

   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, inttmp)   //深搜不停向右

{

    intv = 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);   //反向边

   }

 

    intt = 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;

    intflag = 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);

    intttt; 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);

   }

}

0 0
原创粉丝点击