思路分析:因为坐标相同的点只能选一个(比赛没看到这条件,浪费了2个半小时)...所以当然选择编号最小的最优
从凸包上面走会更优,所以答案的解肯定包括起点,终点,凸包拐点。
假如凸包一条边上有多点共线,那么就要看边上的点编号是否比边的终点编号小,是的话放到答案里解会更优。因为题目求的是字典序最小。
代码如下:
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
typedef long long LL;
struct Point{
LL x,y;
int idx;
Point(){}
Point(LL x, LL y, int idx):x(x),y(y),idx(idx){}
bool operator <(const Point &rhs) const {
if (x != rhs.x) return x<rhs.x;
if (y != rhs.y) return y>rhs.y;
return idx < rhs.idx;
}
};
typedef Point Vector;
Vector operator +(Vector A, Vector B) {return Vector(A.x+B.x,A.y+B.y,0); }
Vector operator -(Vector A, Vector B) {return Vector(A.x-B.x,A.y-B.y,0); }
LL Cross(Vector A, Vector B) {return A.x*B.y-A.y*B.x;}
const int maxn = 2e5+10;
Point p[maxn],ch[maxn];
bool vis[maxn];
int ans[maxn];
LL x,y;
int n,m;
int ConvexHull(Point *p, int n, Point *ch){
int m = 0;
for (int i=0; i<n; ++i) {
if (i>0 && p[i].x == p[i-1].x) continue;
while (m>1 && Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2]) > 0) m--;
ch[m++] = p[i];
}
return m;
}
int main(){
int T; scanf("%d",&T);
while (T--) {
scanf("%d",&n);
for (int i=0; i<n; ++i) {
scanf("%lld%lld",&x,&y);
p[i] = Point(x,y,i+1);
}
sort(p,p+n);
m = ConvexHull(p,n,ch);
memset(vis,0,sizeof(vis));
vis[0] = vis[m-1] = 1; ans[0] = 1; ans[m-1] = n;
for (int i=1; i<m-1; ++i) if (Cross(ch[i]-ch[i-1],ch[i+1]-ch[i-1]) != 0) vis[i] = 1;
for (int i=m-2; i>0; i--) {
if (vis[i]) ans[i] = ch[i].idx;
else ans[i] = min(ans[i+1],ch[i].idx);
}
for (int i=0; i<m-1; ++i) if (ans[i] == ch[i].idx) printf("%d ",ans[i]);
printf("%d\n",n);
}
return 0;
}