AOJ 2121 Castle Wall

21 篇文章 0 订阅

有一个国王想将凹多边形的城堡变为凸多边形,需要毁掉一些墙造新的墙

造新墙的限制条件是:

1. 新墙只能连接原凹多边形的两个顶点。

2. 新墙总长度不超过r

已知所有顶点都在整数格点上,且在第一象限100*100正方形边上或内部。

求最大凸多边形城堡的面积


由于所有点都在整数格点上,所以任意整数格点多边形的面积*2后都是整数。

接下来扫出所有可以连接的边,dp面积即可


要注意由于面积*2了,而且都是有向面积,会有负数,所以最后数组要开到100*100*2*2=40000. 其中100*100是凸多边形的最大面积

接下来输出时除以2即可。



/*author: birdstorm*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <complex>
#include <set>
#include <algorithm>
#include <climits>
#include <cfloat>

#define MAXN 100
//#define N 105
#define inf 1.0e20
//#define eps 1.0e-8
#define MOD 1000000007

#define next(i) (i+1)%sz

#define For(i,m,n) for(int i=(m);i<(n);i++)
#define FORIT(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();++i)
#define rep(i,m,n) for(int i=(m);i<=(n);i++)
#define repd(i,m,n) for(int i=(m);i>=(n);i--)
#define LL long long
#define test

using namespace std;

const double eps=1.0e-8;
const double pi=acos(-1.0);
struct point{
    double x,y;
    point():x(0),y(0){}
    point(double x,double y):x(x),y(y) {}
    point operator + (const point &a) const{
        return point(x+a.x,y+a.y);
    }
    point operator - (const point &a) const{
        return point(x-a.x,y-a.y);
    }
    bool operator < (const point &a) const{
        return x+eps<a.x || abs(x-a.x)<eps && y+eps<a.y;
    }
    bool operator == (const point &a) const{
        return abs(x-a.x)<eps && abs(y-a.y)<eps;
    }
    point operator * (double c) const{
        return point(c*x,c*y);
    }
    point operator / (double c) const{
        return point(x/c,y/c);
    }
};

typedef vector<point> polygon; //POLYGON

inline double cross(point a,point b){
    return a.x*b.y-a.y*b.x;
}
inline double mul(const point &a, const point &b){
    return a.x*b.x+a.y*b.y;
}

int dlcmp(double x){return x<-eps?-1:x>eps;}

struct line{
    point a,b;
    line(){}
    line(const point &a,const point &b):a(a),b(b){}
};

bool intersect(const line &L1,const line &L2){
	return dlcmp(cross(L1.b-L1.a,L2.b-L1.a))*dlcmp(cross(L1.b-L1.a,L2.a-L1.a))<0&&dlcmp(cross(L1.a-L2.a,L2.b-L2.a))*dlcmp(cross(L1.b-L2.a,L2.b-L2.a))<0;
}

bool on_line(point a, point b, point c)
{
    if(dlcmp(cross(a-b,a-c))) return false;
    return dlcmp(mul(a-c,b-c))<0;
}

point p[MAXN];
bool a[MAXN][MAXN];
double x[MAXN], y[MAXN], dp[MAXN][40005];
double dist[MAXN][MAXN];
double r;
int n;
int main()
{
//    freopen("2121-input.txt","r",stdin);
//    freopen("2121-output2.txt","w",stdout);
    int cs=1;
    while(scanf("%d%lf",&n,&r),n){
        int s=0;
        For(i,0,n){
            scanf("%lf%lf",&x[i],&y[i]);
            if(x[i]<x[s]) s=i;
        }
        rep(i,0,n){
            p[i]=point(x[(i+s)%n],y[(i+s)%n]);
        }
        memset(a,0,sizeof a);
        rep(i,0,n){
            rep(j,0,n){
                dist[i][j]=sqrt((p[i].x-p[j].x)*(p[i].x-p[j].x)+(p[i].y-p[j].y)*(p[i].y-p[j].y));
            }
        }
        double Area;
        For(i,0,n){
            rep(j,i+2,n){
                if(i==0&&j==n) continue;
                For(k,0,n){
                    if(k==i||k==j%n) continue;
                    if(on_line(p[i],p[j],p[k])){
                        goto illegal;
                    }
                }
                For(k,0,n){
                    if(intersect(line(p[i],p[j]),line(p[k],p[k+1]))){
                        goto illegal;
                    }
                }
                Area=cross(p[i],p[j]);
                for(int k=j-1; k>=i; k--){
                    Area+=cross(p[k+1],p[k]);
                }
                if(Area<=eps){
                    goto illegal;
                }
                a[i][j]=true;
                continue;
                illegal:
                    a[i][j]=false;
            }
        }
        rep(i,0,n){
            For(j,0,40001){
                dp[i][j]=1.0e20;
            }
        }
        dp[0][20000]=0.0;
        For(i,0,n){
            rep(j,0,40000){
                if(dp[i][j]>=1.0e20) continue;
                int S=floor(cross(p[i],p[i+1])+eps);
                dp[i+1][j+S]=min(dp[i+1][j+S],dp[i][j]);
                rep(k,i+2,n){
                    if(a[i][k]){
                        S=floor(cross(p[i],p[k])+eps);
                        dp[k][j+S]=min(dp[k][j+S],dp[i][j]+dist[i][k]);
                    }
                }
            }
        }
        int ret=0;
        For(i,20000,40001){
            if(dp[n][i]<=r) ret=i-20000;
        }
        printf("case %d: %.1f\n",cs++,(double)ret/2.0);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值