1. 程式人生 > 實用技巧 >hdu6325 Interstellar Travel 變形凸包

hdu6325 Interstellar Travel 變形凸包

題目:給出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("\n"); } return 0; }
View Code