POJ 1696
这题是明显的TU包变形。
使用卷包裹法可解,而且是必定可以经过所有点的。直观可知,当经过某点后,相当于把之前的点抹去,求剩下点的TU包,递归下去,也就能把点全部经过了。
于是,只需把经过的点标记一下就可以了。
#include <iostream> #include <cstdio> #include <algorithm> #include <queue> #include <cmath> using namespace std; const double inf=10000000; const double eps=0.00000001; struct point { double x,y; int num; }p[60]; bool vis[60]; queue<int>que; struct vect{ double x,y; }; double dist(point a,point b){ return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } double cross(point a,point b,point c,point d){ return (a.x-b.x)*(c.y-d.y)-(a.y-b.y)*(c.x-d.x); } int n; int main(){ int t; scanf("%d",&t); double a,b; while(t--){ scanf("%d",&n); point start; start.x=inf; start.y=inf; int dep; for(int i=0;i<n;i++){ scanf("%d%lf%lf",&p[i].num,&p[i].x,&p[i].y); if(p[i].y<start.y){ start.x=p[i].x; start.y=p[i].y; start.num=p[i].num; dep=i; } else if(p[i].y==start.y){ if(p[i].x<start.x){ start.x=p[i].x; start.num=p[i].num; dep=i; } } } // cout<<start.x<<' '<<start.y<<endl; point last; last.x=0; last.y=start.y; que.push(start.num); memset(vis,false,sizeof(vis)); vis[dep]=true; point tmp; while(true){ bool flag=false; for(int i=0;i<n;i++){ if(vis[i]==false){ if(cross(start,last,p[i],start)>=0){ tmp=p[i]; dep=i; flag=true; break; } } } // cout<<dep<<"YES"<<endl; if(!flag) break; for(int i=0;i<n;i++){ if(vis[i]==false){ if(cross(start,last,p[i],start)<0) continue; double res=cross(tmp,start,p[i],start); if(res<0){ tmp=p[i]; dep=i; } else if(res==0){ if(dist(p[i],start)+eps<dist(tmp,start)){ tmp=p[i]; dep=i; } } } } que.push(tmp.num); //cout<<dep<<endl; vis[dep]=true; last=start; start=tmp; } printf("%d",n); for(int i=0;i<n;i++){ printf(" %d",que.front()); que.pop(); } printf("\n"); } return 0; }