Poj-1696-Space Ant

来源:互联网 发布:linux串口读写程序 编辑:程序博客网 时间:2024/05/21 06:22
Description
The most exciting space discovery occurred at the end of the 20th century. In 1999, scientists traced down an ant-like creature in the planet Y1999 and called it M11. It has only one eye on the left side of its head and just three feet all on the right side of its body and suffers from three walking limitations: 
It can not turn right due to its special body structure. 
It leaves a red path while walking. 
It hates to pass over a previously red colored path, and never does that.
The pictures transmitted by the Discovery space ship depicts that plants in the Y1999 grow in special points on the planet. Analysis of several thousands of the pictures have resulted in discovering a magic coordinate system governing the grow points of the plants. In this coordinate system with x and y axes, no two plants share the same x or y. 
An M11 needs to eat exactly one plant in each day to stay alive. When it eats one plant, it remains there for the rest of the day with no move. Next day, it looks for another plant to go there and eat it. If it can not reach any other plant it dies by the end of the day. Notice that it can reach a plant in any distance. 
The problem is to find a path for an M11 to let it live longest. 
Input is a set of (x, y) coordinates of plants. Suppose A with the coordinates (xA, yA) is the plant with the least y-coordinate. M11 starts from point (0,yA) heading towards plant A. Notice that the solution path should not cross itself and all of the turns should be counter-clockwise. Also note that the solution may visit more than two plants located on a same straight line. 


Input
The first line of the input is M, the number of test cases to be solved (1 <= M <= 10). For each test case, the first line is N, the number of plants in that test case (1 <= N <= 50), followed by N lines for each plant data. Each plant data consists of three integers: the first number is the unique plant index (1..N), followed by two positive integers x and y representing the coordinates of the plant. Plants are sorted by the increasing order on their indices in the input file. Suppose that the values of coordinates are at most 100.
Output
Output should have one separate line for the solution of each test case. A solution is the number of plants on the solution path, followed by the indices of visiting plants in the path in the order of their visits.
Sample Input
2
10
1 4 5
2 9 8
3 5 9
4 1 7
5 3 2
6 6 3
7 10 10
8 8 1
9 2 4
10 7 6
14
1 6 11
2 11 9
3 8 7
4 12 8
5 9 20
6 3 2
7 1 6
8 2 13
9 15 1
10 14 17
11 13 19
12 5 18
13 7 3
14 10 16


Sample Output
10 8 7 3 4 9 5 6 2 1 10

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

题目意思大概是给你一个数n,然后有n个例子,然后每个例子都会先给你一个数m,然后接下来的m行,分别代表有三个数,第一个代表点的编号,后两个代表点的坐标,让你从y坐标最小的点作为起点,然后向你的右侧的点连线,再从那个点再向它自己的右侧连线,每个点只能连一次,连线不能交叉,看最多能连多少个,输出最多能连多少个点以及它们的编号顺序。

思路:这是一道有关凸包的题,由凸包的性质我们可以判断一定存在一种方式能将所有的点都能连起来。我们可以采用枚举比较的方法来确定下一个被连到的点。首先我们选出起点,标记,放入数组,然后找一个没有被标记走过的点,让它和起点的连线和除它之外每个没有被标记的点和起点连线进行叉乘,判断此点是否在右边,不是则更新,是则继续比较,如果三点一线,则选取距离起点近的点,这样一轮枚举下来,我们就得到了下一个该连的点的编号,将其标记,放入数组,此时以其作为新的起点,然后循环m-1次,则可得到所有点的次序。

代码如下:

#include <algorithm>
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
using namespace std;
struct note{
    double x;
    double y;
    int z;
};
//存点和编号
struct note a[105];
//标记数组
int book1[105];
//存路线的数组
int book2[105];
//求两点的距离
double juli(note p,note q)
{
    return sqrt((q.x-p.x)*(q.x-p.x)+(q.y-p.y)*(q.y-p.y));
}
//判断点在直线的左边还是右边或其上
int chacheng(note p,note q1,note q2)
{
    if((q1.x-p.x)*(q2.y-p.y)-(q2.x-p.x)*(q1.y-p.y)>0)
        return -1;
    else if((q1.x-p.x)*(q2.y-p.y)-(q2.x-p.x)*(q1.y-p.y)==0)
        return 0;
    else
        return 1;
}
int main()
{
    int n;
    scanf("%d",&n);
    while(n--)
    {
        //标记清零
        memset(book1,0,sizeof(book1));
        int m;
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
            scanf("%d %lf %lf",&a[i].z,&a[i].x,&a[i].y);
        //找出起点
        int Max=999;
        int book;
        for(int i=1;i<=m;i++)
            if(a[i].y<Max)
            {
                Max=a[i].y;
                book=i;
            }
        //标记
        book1[book]=1;
        book2[1]=book;
        //数组模拟队列的下标,将起点放入队列
        int p=1;
        book2[p]=book;
        int jishu=1;
        while(jishu<m)
        {
            int k;
            //访问队首元素
            int d=book2[p];
            //选取当前要连的下一点
            for(int i=1;i<=m;i++)
            {
                if(book1[i]!=1)
                {
                    k=i;
                    break;
                }
            }
            //将其与除己之外的其它没有标记的点进行比较
            for(int i=1;i<=m;i++)
            {
                if(k!=i&&book1[i]!=1)
                {
                    //如果i点在起点与k连线的右边,更新
                    if(chacheng(a[d],a[k],a[i])==1)
                        k=i;
                    //如果三点一线,选距离起点近的点
                    else if(chacheng(a[d],a[k],a[i])==0)
                        if(juli(a[d],a[k])>juli(a[d],a[i]))
                            k=i;
                    else
                        continue;
                }
            }
            //将队首出队
            p++;
            //在队中放入新元素
            book2[p]=k;
            //标记
            book1[k]=1;
            jishu++;
        }
        //输出
        printf("%d ",m);
        for(int i=1;i<m;i++)
            printf("%d ",book2[i]);
        printf("%d\n",book2[m]);
    }
    return 0;
}

0 0
原创粉丝点击