题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=1348
凸包模板:
const int N =1010; const double PI = 3.1415927; double EPS=1e-10; // 考虑误差的加法运算 double add(double a,double b) { if(fabs(a+b)<EPS*(fabs(a)+fabs(b))) return 0; return a+b; } struct Point{ double x,y; Point(){} Point(double x,double y):x(x),y(y){} // 构造函数,方便代码编写 Point(const Point & p):x(p.x),y(p.y){} Point operator +(Point p){ return Point(add(x,p.x), add(y,p.y)); } Point operator-(Point p){ return Point(add(x,-p.x),add(y,-p.y)); } Point operator*(double d){ return Point(x*d,y*d); } double operator*(Point p){ // 内积 点乘 return add(x*p.x, y*p.y); } double operator^(Point p){// 外积 叉乘 return add(x*p.y,-y*p.x); } friend ostream& operator<<(ostream& os,const Point& p ){ os<<p.x<<" "<<p.y<<endl; return os; } friend istream& operator>>(istream& is, Point& rh) {// Point 不能是常量,是变量 is>>rh.x>>rh.y; return is; } double dist(Point p){ return sqrt( add( (x-p.x)*(x-p.x),(y-p.y)* (y-p.y) ) ); } }; Point List[N]; // 输入点集Q Point stack[N]; // 栈从低到顶部包含了按逆时针方向排列在CH(Q)(凸包)中的各个顶点。 int top; // 栈顶 bool cmp(Point a,Point b) { if(a.y!= b.y) return a.y<b.y; else return a.x<b.x; } // 按极角排序,如果极角相等则按距离从小到大,sort是按从小到大排列的,故需对<符号重载 bool operator<(Point p1,Point p2) { double tmp=(p1-List[0])^(p2-List[0]); //List[0]为基点 if(tmp>0) return 1; else if(tmp==0 && p1.dist(List[0])< p2.dist(List[0])) return 1; else return 0; } // 输入点集Q,并把最左下方的点放在 LIst[0],作为基点, //并且进行极角排序,对sort(list+1,List+n) ,最大时间O(nlgn) void init(int n) { for(int i=1;i<n;i++) cin>>List[i]; sort(List, List+n,cmp); // List[0] 存储的是 左下方的点 sort(List+1,List+n); // 对 List[1]~ List[n-1] 进行对 List[0]的极角排序 } // 寻找凸包 graham 扫描法 时间O(n) void graham(int n) { if(n==1) {top=0; stack[0]=List[0];} if(n==2) { top=1; stack[0]=List[0]; stack[1]=List[1]; } if(n>2) { for(int i=0;i<=1;i++) // 初始化栈,有p0,p1进栈 stack[i]=List[i]; top=1; for(int i=2;i<n;i++) { while(top>=1 && ((stack[top]-stack[top-1])^(List[i]-stack[top-1]))<=0) // 非左转 top--; // 删除栈顶元素 top++; stack[top]=List[i]; // 将i压入栈 } } }
hdu 1348 求凸包的周长 + 圆周长
http://acm.hdu.edu.cn/showproblem.php?pid=1348
代码如下:
#include <iostream> #include <algorithm> #include <stdlib.h> #include <iostream> #include <stdio.h> #include <string> #include <string.h> #include <vector> #include <set> #include <math.h> #include <cmath> #include <map> #include <queue> using namespace std; typedef long long ll; const int N =1010; const double PI = 3.1415927; double EPS=1e-10; // 考虑误差的加法运算 double add(double a,double b) { if(fabs(a+b)<EPS*(fabs(a)+fabs(b))) return 0; return a+b; } struct Point{ double x,y; Point(){} Point(double x,double y):x(x),y(y){} // 构造函数,方便代码编写 Point(const Point & p):x(p.x),y(p.y){} Point operator +(Point p){ return Point(add(x,p.x), add(y,p.y)); } Point operator-(Point p){ return Point(add(x,-p.x),add(y,-p.y)); } Point operator*(double d){ return Point(x*d,y*d); } double operator*(Point p){ // 内积 点乘 return add(x*p.x, y*p.y); } double operator^(Point p){// 外积 叉乘 return add(x*p.y,-y*p.x); } friend ostream& operator<<(ostream& os,const Point& p ){ os<<p.x<<" "<<p.y<<endl; return os; } friend istream& operator>>(istream& is, Point& rh) {// Point 不能是常量,是变量 is>>rh.x>>rh.y; return is; } double dist(Point p){ return sqrt( add( (x-p.x)*(x-p.x),(y-p.y)* (y-p.y) ) ); } }; Point List[N]; // 输入点集Q Point stack[N]; // 栈从低到顶部包含了按逆时针方向排列在CH(Q)(凸包)中的各个顶点。 int top; // 栈顶 bool cmp(Point a,Point b) { if(a.y!= b.y) return a.y<b.y; else return a.x<b.x; } // 按极角排序,如果极角相等则按距离从小到大,sort是按从小到大排列的,故需对<符号重载 bool operator<(Point p1,Point p2) { double tmp=(p1-List[0])^(p2-List[0]); //List[0]为基点 if(tmp>0) return 1; else if(tmp==0 && p1.dist(List[0])< p2.dist(List[0])) return 1; else return 0; } // 输入点集Q,并把最左下方的点放在 LIst[0],作为基点, //并且进行极角排序,对sort(list+1,List+n) ,最大时间O(nlgn) void init(int n) { for(int i=0;i<n;i++) cin>>List[i]; sort(List, List+n,cmp); // List[0] 存储的是 左下方的点 sort(List+1,List+n); // 对 List[1]~ List[n-1] 进行对 List[0]的极角排序 } // 寻找凸包 graham 扫描法 时间O(n) void graham(int n) { if(n==1) {top=0; stack[0]=List[0];} if(n==2) { top=1; stack[0]=List[0]; stack[1]=List[1]; } if(n>2) { for(int i=0;i<=1;i++) // 初始化栈,有p0,p1进栈 stack[i]=List[i]; top=1; for(int i=2;i<n;i++) { while(top>=1 && ((stack[top]-stack[top-1])^(List[i]-stack[top-1]))<=0) // 非左转 top--; // 删除栈顶元素 top++; stack[top]=List[i]; // 将i压入栈 } } } int main() { int T,count=0,n; double r; cin>>T; while(T--) { if(count) cout<<endl; count=1; cin>>n>>r; init(n); graham(n); double ans=0; for(int i=0;i<top;i++) ans+=stack[i].dist(stack[i+1]); ans+=stack[top].dist(stack[0]); ans+=2*PI*r; printf("%.0lf ",ans); } return 0; }