poj 1113 Wall

题意:国王要求建一堵墙围绕他的城堡,且城堡与墙的距离总不小于一个数L,要求求最小的墙壁周长。


分析:直接求出凸包然后加上半径为L的圆的周长,对于证明却有点不太理解~。用卷包裹发求出凸包上的点,然后算出凸包的周长,加上圆的周长即为所求。

PS:我的程序不能求出凸包上所有的点,对于共线的情况只能取最远的一点,还没想到一个好办法解决。


以下附上代码:

#include <algorithm>
#include <iostream>
#include <sstream>
#include <fstream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cctype>
#include <cmath>
#include <stack>
#include <queue>
#include <list>
#include <map>
#include <set>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;

const double pi = acos(-1.0);
const int maxn = 1005;

struct Point{
  int x,y;
  
  Point(){}
  Point(int x_, int y_) :
    x(x_), y(y_) {}
  
  bool operator < (const Point b) const{
    if(y != b.y) return y < b.y;
    return x < b.x;
  }
  
  bool operator != (const Point b) const{
    return x != b.x || y != b.y;
  }
  
  bool operator == (const Point b) const{
    return x == b.x && y == b.y;
  }
  
  Point operator - (const Point b) const{
    Point t(x-b.x,y-b.y);
    return t;
  }
  
  int operator * (const Point b) const{
    return x*b.x + y*b.y;
  }
  
  int operator ^ (const Point b) const{
    return x*b.y - y*b.x;
  }
  
  int len2(){
    return x*x+y*y;
  }
};




int n,l;
Point x[maxn];
int ans[maxn];
int cnt;

void input()
{
  for(int i = 0; i < n; i++){
    scanf("%d%d",&x[i].x,&x[i].y);
  }
}

void solve()
{
  sort(x,x+n);
    
  cnt = 0;
  ans[cnt++] = 0;
  Point v1,v2;//vector
  int index;
  while(cnt == 1 || ans[cnt-1] != 0){
    for(int  i = n-1; i >= 0; i--){
      if(i == ans[cnt-1]) continue;
      v1 = x[i] - x[ans[cnt-1]];
      index = i;  
      break;
    }
    
    for(int i = 0; i < n; i++){
      if(i == ans[cnt-1] || i == index) continue;  
      v2 = x[i] - x[ans[cnt-1]];  
      if((v1^v2) < 0){
        v1 = v2;
        index = i;
      }
      else if((v1^v2) == 0 && v1.len2() < v2.len2()){
          v1 = v2;
          index = i;
      }
    }
    ans[cnt++] = index;
  }//end of while
  Point v;
  double sum = 0.0;
  
  for(int i = 1; i < cnt; i++){
    v = x[ans[i]] - x[ans[i-1]];
    sum += sqrt(1.0*v.len2());
  }
  double res = sum;
  res += 2 * pi * l;
  printf("%.0lf\n",res);
}


int main()
{
  while(scanf("%d%d",&n,&l) != EOF){
    input();
    solve();
  }
	return 0;
}


Graham:

#include <algorithm>
#include <iostream>
#include <sstream>
#include <fstream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cctype>
#include <cmath>
#include <stack>
#include <queue>
#include <list>
#include <map>
#include <set>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;

const double pi = acos(-1.0);
const int maxn = 1005;

struct Point{
  int x,y;
  
  Point(){}
  Point(int x_, int y_) :
    x(x_), y(y_) {}
    
  //point
  
  bool operator < (const Point &b) const{
    if(x != b.x) return x < b.x;
    return y < b.y;
  }
  
  Point operator - (const Point &b) const{
    Point t(x-b.x,y-b.y);
    return t;
  }
  
  //vector
  int operator ^ (const Point &b) const{
    return x*b.y - y*b.x;
  }
  
  int len2(){
    return x*x + y*y;
  }
  
};


int n,l;
Point p[maxn];
int res[maxn];
int cnt;

void input()
{
  for(int i = 0; i < n; i++){
    scanf("%d%d",&p[i].x,&p[i].y);
  }
}

bool cmp(Point a, Point b)
{
  Point v1 = a - p[0];
  Point v2 = b - p[0];
  if((v1 ^ v2) != 0) return (v1 ^ v2) > 0;
  return v1.len2() < v2.len2();
}

void Graham()
{
  cnt = 0;
  sort(p,p+n);
  sort(p+1,p+n,cmp);
  if(n == 0) return; res[cnt++] = 0;
  if(n == 1) return; res[cnt++] = 1;
  if(n == 2) return;
  
  Point v1,v2;
  for(int i = 2; i < n; i++){
    while(cnt){
      v1 = p[res[cnt-1]] - p[res[cnt-2]];
      v2 = p[i] - p[res[cnt-1]];
      if((v1 ^ v2) >= 0) break;
      --cnt;
    }
    
    res[cnt++] = i;
  }
  
  
}

void solve()
{
  Graham();
  double ans = 0.0;
  Point v;
  for(int i = 1; i < cnt; i++){
    v = p[res[i]] - p[res[i-1]];
    ans += sqrt(1.0*v.len2());
  }
  v = p[0] - p[res[cnt-1]];
  ans += sqrt(1.0*v.len2());
  ans += 2 * pi * l;
  printf("%.0lf\n",ans);
}

int main()
{
  while(scanf("%d%d",&n,&l) != EOF){
    input();
    solve();
  }
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值