题目:给出n个平面坐标,保证第一个点和第n个点y值为0,其余点的x坐标都在中间,要从 i 点走到 j 点的要求是 i 点的横坐标严格小于 j 的横坐标,并且消耗的能量是(xi * yj - xj * yi),要求消耗的能量最小(能量可以为负),并且字典序要求最小。
思路:说实话我一开始真没啥思路,最后还是看了题解才知道往凸包上想,菜!大概就是消耗的能量可以是负的,而且该起点为为(0,0)所以x1y2-x2y1等价于所求凸包面积的负值,要想耗费的能量最小,那么就是多边形的面积最大,即凸包!(若第一个点不是(0,0)所有其他的点都减去第一个点的坐标,用相对坐标求即可)求字典序最小的话,就是有可能在一条线段上有多个点,尝试取每一个点,若可以减少字典序,就加进去即可!
#include<iostream> #include<cstring> #include<cmath> #include<algorithm> #include<cstdio> #include<vector> #include<map> #include<set> #include<queue> #include<stack> //#define _for(i,a,b) for(int i=a;i<=b;i++) using namespace std; typedef long long ll; double eps=0.05; ll mod=1e9+7; const int INF=0x3f3f3f3f,inf =0x3f3f3f3f; const int MAXN=2e3+10; const int maxn = 1e7+10; const double PI=acos(-1.0); //ll inf=100000000000000; //template<typename T>inline void read(T &x) //{ // x=0; // static int p;p=1; // static char c;c=getchar(); // while(!isdigit(c)){if(c=='-')p=-1;c=getchar();} // while(isdigit(c)) {x=(x<<1)+(x<<3)+(c-48);c=getchar();} // x*=p; //} typedef unsigned long long ull; const int N=2e5+7; struct node{ int x,y; int ps; bool operator <(node &p){ if(x!=p.x)return x<p.x; if(y!=p.y)return y>p.y; return ps<p.ps; } }p[N]; int que[N],mn[N]; ll cross(int x,int y,int z){ int ax=p[y].x-p[x].x; int ay=p[y].y-p[x].y; int bx=p[z].x-p[y].x; int by=p[z].y-p[y].y; return 1ll*ax*by-1ll*bx*ay; } int main() { int t; scanf("%d",&t); while(t--){ int n; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d%d",&p[i].x,&p[i].y); for(int i=1;i<=n;i++)p[i].ps=i; sort(p+1,p+n+1); int now=0; for(int i=2;i<=n;i++){ if(p[i].x==p[i-1].x)continue; while(now&&cross(que[now-1],que[now],i)>0)now--; que[++now]=i; } int l=0,r; printf("1"); while(l<now){ for(r=l+1;r<=now;r++){ if(cross(que[l],que[l+1],que[r])!=0)break; } mn[r]=1e9; for(int i=r-1;i>=l;i--){ mn[i]=min(mn[i+1],p[que[i]].ps); } for(int i=l+1;i<=r-1;i++){ if(mn[i]==p[que[i]].ps)printf(" %d",p[que[i]].ps); } l=r-1; } printf(" "); } return 0; }