POJ 1696 Space Ant
大致题意:
一只蚂蚁,只会向左转,现在给出平面上很多个点,求解一种走法,
能使得蚂蚁能经过的点最多,每个顶点该蚂蚁只能经过一次,且所行走的路线不能发生交叉.
输入
输入的第一行是m,要测试的测试用例的数量(1 < = T=10)。对于每一个测试用例,第一行是n,测试用例中的点数量(1 < = n=50),其次是每个点数据的n行。每个植物数据由三个整数组成:第一个数字是编号其次是两个正整数x和y代表植物的坐标。根据输入文件中索引的递增顺序对植物进行排序。假设坐标的值最多为100。
输出
输出应该有一个单独的行,用于每个测试用例的解决方案。一个解决方案是植物在溶液路径上的数量,其次是按照访问顺序在路径上访问植物的索引。
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
题解:凸包卷包裹法,用凸包覆盖点可以用这个算法,复杂度O(n^2)
首先,了解一下叉积的性质:l1和l2叉积小于0代表l2在l1右边
根据凸包性质,可以知道,本题必有全解,想得到解,贪心每一次选偏转最小的点,即极角最小。
首先选出y最小的点s,此时没有点在他右边,随便选出一点k
枚举i,比对sk和si线段的叉积,小于0则k=i,依次类推,一层循环得到最靠右极角最小的点s'
同样对s'处理
那么可能会有问题,对于得到的s',因为最靠右,有没有可能朝向右边?
答案是没有
如果对于点s'选中朝右的点,那么s就存在更靠右的值,所以s不会选s'矛盾
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<iostream> 5 #include<cmath> 6 using namespace std; 7 double x[1001],y[1001],minn; 8 bool vis[10001]; 9 int n,cnt; 10 double distan(double x1,double y1,double x2,double y2) 11 { 12 return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); 13 } 14 double cross(double xx,double yy,double x1,double y1,double x2,double y2) 15 { 16 double dx=x1-xx,dy=y1-yy; 17 double fx=x2-xx,fy=y2-yy; 18 return (dx*fy-fx*dy); 19 } 20 int main() 21 {int T,i,pn,now,nxt,p[1001]; 22 cin>>T; 23 while (T--) 24 { 25 memset(vis,0,sizeof(vis)); 26 scanf("%d",&n); 27 for (i=1;i<=n;i++) 28 { 29 scanf("%d%lf%lf",&pn,&x[i],&y[i]); 30 } 31 now=0;minn=2e9; 32 for (i=1;i<=n;i++) 33 if (y[i]<minn) 34 { 35 minn=y[i];now=i; 36 } 37 cnt=0; 38 vis[now]=1; 39 p[1]=now; 40 cnt++; 41 while (1) 42 { 43 for (i=1;i<=n;i++) 44 if (vis[i]==0) 45 { 46 nxt=i; 47 break; 48 } 49 for (i=1;i<=n;i++) 50 if (vis[i]==0&&i!=nxt) 51 { 52 if (cross(x[now],y[now],x[nxt],y[nxt],x[i],y[i])<0) 53 nxt=i; 54 else if (cross(x[now],y[now],x[nxt],y[nxt],x[i],y[i])==0) 55 if (distan(x[now],y[now],x[i],y[i])<distan(x[now],y[now],x[nxt],y[nxt])) 56 nxt=i; 57 } 58 now=nxt; 59 cnt++; 60 p[cnt]=now; 61 vis[now]=1; 62 if (cnt==n) break; 63 } 64 cout<<n<<' '; 65 for (i=1;i<=n;i++) 66 printf("%d ",p[i]); 67 printf("\n"); 68 } 69 }