• POJ1696Space Ant


    转载请注明出处:優YoU http://user.qzone.qq.com/289065406/blog/1302880751

     

    大致题意:

    一只蚂蚁,只会向左转,现在给出平面上很多个点,求解一种走法,
    能使得蚂蚁能经过的点最多,每个顶点该蚂蚁只能经过一次,且所行走的路线不能发生交叉.

     

    解题思路:

    凸包的入门水题,是凸包的一个变形
    网上看到很多人copy别人的,说什么“极坐标排序”,那是Graham Scan Algoruthm的做法!虽然Graham只有O(nlogn) ,但是这题完全没必要用它,因为题目的规模很小,我用卷包裹算法照样0 ms 一次AC 。确实理论上卷包裹的O(n^2)不如Graham快,但是规模这么小的题目是反映不出来的。

    Graham能不用就不用,一代码超长超烦,特别是散点集排序。看过算法理论的同学,一般都宁愿用极坐标而不用水平序,但是极坐标排序的比较规则特容易出错。水平排序我没看懂,估计其他菜鸟们也差不多。

     

    解题的例图题目已经给出,我就不贴了,反正最终的路线就是螺旋形的。要求从 纵坐标 最小的点作为出发点,这个在输入时顺便找出来,可以节省一点点时间= =

    其实无论输入什么样的点集,一定可以走完全部n个点的,这是凸包的性质决定,所以就放手去做了,不用担心走不完的情况

     

    唯一注意的是,前面提到过时凸包的变形,是因为螺旋线是不封闭的,凸包是封闭的。要想不封闭很简单,做一个标记就可以了,每构造一个凸包顶点,就标记该点,不再与其连线

    当连线完前面n-1个点后,第n个点(最后没被标记的点)就不用再做了,一定是最后一点,输出它就可以了

     

    其他细节参见我的程序, 卷包裹算法 百度就有了,这里我就不多说了

     

      1 //Memory Time 
    2 //228K 0MS
    3
    4 #include<iostream>
    5 using namespace std;
    6
    7 const int inf=101;
    8
    9 typedef class
    10 {
    11 public:
    12 int x,y;
    13 }point;
    14
    15 /*AB距离平方*/
    16
    17 int distsquare(point A,point B)
    18 {
    19 return (B.x-A.x)*(B.x-A.x)+(B.y-A.y)*(B.y-A.y);
    20 }
    21
    22 /*叉积计算*/
    23
    24 int det(int x1,int y1,int x2,int y2)
    25 {
    26 return x1*y2-x2*y1;
    27 }
    28
    29 int cross(point A,point B,point C,point D)
    30 {
    31 return det(B.x-A.x , B.y-A.y , D.x-C.x , D.y-C.y);
    32 }
    33
    34 int main(int i)
    35 {
    36 int test;
    37 cin>>test;
    38 while(test--)
    39 {
    40 int n; //n个点
    41 cin>>n;
    42 point* node=new point[n+1]; //n个点坐标
    43 int* conbag=new int[n+1]; //凸包顶点(根据顶点构造顺序,依次记录node[]下标)
    44 bool* vist=new bool[n+1]; //标记已作为凸包顶点的点
    45
    46 /*Input*/
    47
    48 int min_y=inf; //最小纵坐标值
    49 int fi=0;
    50 for(i=1;i<=n;i++)
    51 {
    52 int num;
    53 cin>>num>>node[i].x>>node[i].y;
    54 vist[i]=false;
    55
    56 if(min_y > node[i].y)
    57 {
    58 min_y = node[i].y;
    59 fi=i;
    60 }
    61 }
    62 conbag[1]=fi; //起点
    63 conbag[0]=1; //凸包顶点计数器
    64 vist[fi]=true;
    65
    66 /*Structure Convex bag*/
    67
    68 int pc=1; //conbag[]指针
    69 while(true)
    70 {
    71 int s=conbag[pc]; //最新的凸包顶点
    72 int k; //当前待加入的凸包顶点
    73 for(i=1;i<=n;i++) //寻找当前基准向量sk,k取任意没标记的点就可以了
    74 if(!vist[i])
    75 {
    76 k=i;
    77 break;
    78 }
    79
    80 for(i=1;i<=n;i++) //枚举没标记的点i,计算sk X si的值,寻找最优(最外面的)k点作为凸包顶点
    81 if(i!=k && !vist[i])
    82 {
    83 int temp=cross(node[s],node[k],node[s],node[i]);
    84
    85 if(temp<0)
    86 k=i;
    87 else if(temp==0)
    88 if(distsquare(node[s],node[k]) > distsquare(node[s],node[i])) //当k i共线时,距离s近的点优先选取
    89 k=i;
    90 }
    91
    92 conbag[++pc]=k; //更新凸包顶点
    93 conbag[0]++;
    94 vist[k]=true;
    95
    96 if(n-conbag[0]==1) //处理完前面n-1个点后 第n个点不再处理
    97 break;
    98 }
    99
    100 cout<<conbag[0]+1<<' '; //这里输出n也可以的
    101
    102 fi=0;
    103 for(i=1;i<=conbag[0];i++)
    104 {
    105 cout<<conbag[i]<<' '; //输出前面n-1个点的同时寻找第n个没标记的点
    106 if(!vist[i])
    107 fi=i;
    108 }
    109 if(fi)
    110 cout<<fi<<endl;
    111 else
    112 cout<<n<<endl;
    113
    114 delete node;
    115 delete conbag;
    116 delete vist;
    117
    118 }
    119 return 0;
    120 }
    [ EXP技术分享博客 ] 版权所有,转载请注明出处: http://exp-blog.com
  • 相关阅读:
    浏览器切换窗口事件
    icheck的使用
    datetimepicker —— 日期选择控件
    apktool
    生成证书
    Jadx
    js call、apply和bind
    1号台风来了
    Linux内核编译和测试
    华中科技大学电子地图
  • 原文地址:https://www.cnblogs.com/lyy289065406/p/2122831.html
Copyright © 2020-2023  润新知