Poj-1696-Space Ant

博客介绍了如何解决Poj-1696-Space Ant问题,这是一个涉及凸包性质的算法题目。通过枚举和叉乘判断,找到从y坐标最小的点开始,按照不交叉原则连接所有点的最大数量和顺序。代码实现中,使用了结构体存储点的信息,计算两点间距离和判断点相对于直线的位置,最终得出所有点的连接顺序。
摘要由CSDN通过智能技术生成
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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值