题意:一只蚂蚁,爬行时不能右转,不能经过自己爬过的路径。它去吃坐标系(第一象限)里的一些植物,起点在x=0,y=植物的最小纵坐标处。问以什么顺序吃,能吃到最多,输出吃到的植物数和顺序。
思路:其实,蚂蚁一定能吃到所有的植物,这是个坑。它的爬行轨迹是一条螺旋线,能经过所有的点。y最小中x最小的点肯定是第一个点,初始方向为x轴正方向。维护一个当前方向(或者说是上一个点和当前点),然后枚举每一个没有经过的点,拐角(利用点积的性质计算,因为角的范围是[0,pi],余弦函数在此区间单调)最小的为下一个点,如果多个点拐角相等(浮点数不好直接比较,另写一个函数),则选择最近的点。
#include <iostream>
#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include <cstdlib>
#include <string>
#include <memory.h>
#include <vector>
#include <queue>
#include <stack>
#include <ctype.h>
using namespace std;
struct point{
int x;
int y;
};
point pt[110];
bool used[110];
bool equal(double a,double b){//绝对值很小认为相等
if(abs(a-b)<0.000001)return true;
return false;
}
int dp(int x1,int y1,int x2,int y2){//点积
return (x1*x2+y1*y2);
}
double dist(point p1,point p2){//
return sqrt(((double)p1.x-p2.x)*(p1.x-p2.x)+((double)p1.y-p2.y)*(p1.y-p2.y));
}
int main(){
int M;
cin>>M;
while(M--){
memset(used,0,sizeof(used));
int N;
cin>>N;
int starty=INT_MAX;
int startx;
int starti;
for(int i=1;i<=N;i++){
int a;
cin>>a;
cin>>pt[a].x>>pt[a].y;
if(pt[a].y<starty){
starty=pt[a].y;startx=pt[a].x;starti=i;
}
}
used[starti]=true;
point last;
last.x=0;last.y=starty;
point cur;
cur.x=startx;cur.y=starty;
cout<<N<<" "<<starti<<" ";
for(int i=1;i<N;i++){
double maxangle=-1.1;
int key;
for(int j=1;j<=N;j++){
if(used[j])continue;
int dpval=dp(cur.x-last.x,cur.y-last.y, pt[j].x-cur.x,pt[j].y-cur.y);
if(equal(dpval/dist(last,cur)/dist(cur,pt[j]),maxangle)){
if(dist(cur,pt[j])<dist(cur,pt[key])){
maxangle=dpval/dist(last,cur)/dist(cur,pt[j]);
key=j;
}
continue;
}
if(dpval/dist(last,cur)/dist(cur,pt[j])>maxangle){
maxangle=dpval/dist(last,cur)/dist(cur,pt[j]);
key=j;
}
}
last.x=cur.x;last.y=cur.y;
cur.x=pt[key].x;cur.y=pt[key].y;
used[key]=true;
cout<<key;
if(i==(N-1)){
cout<<endl;
}else{
cout<<" ";
}
}
}
return 0;
}