可怜的牧羊人
Posted linxif2008
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了可怜的牧羊人相关的知识,希望对你有一定的参考价值。
可怜的牧羊人
题目描述:
阿里是一个老实巴交的牧羊人,他有一块地,这块地周边插着一些树桩,阿里用一根粗绳顺次把这些树桩连接起来,构成一个凸多边形,这个多边形就是他的牧羊场。阿里就是靠自己辛勤的劳动卖羊毛挣钱的。过冬了,今年特别冷,所以羊毛的销量特别好,阿里非常高兴。然而住在附近的一个财主看到阿里的收入十分眼红,他在阿里牧场的某些地方下了毒药,想毒死阿里的绵羊。阿里知道了这件事情,但他知道自己斗不过财主,他只能忍受,他所能做的就是把自己的牧羊场缩小,即挑选一些树桩,用绳子重新把牧羊场按顺序围成,以保证牧羊场里的草没有毒药。阿里不希望自己的牧羊场被分隔开,所以围成牧羊场后任意两段绳子除在树桩点外不能相交。他希望新的牧羊场面积尽可能大。但不知道具体是多少,你能帮他算出来么?
输入格式:
第一行是一个整数(n) ((1 leq n leq 100)),表示树桩的数目。接下来又(n)行,每行两个整数(X_i), (Y_i) ( $ |X_i| leq 10000 $ , $ |Y_i| leq 10000 $ ) , 按逆时针顺序给出每个树桩所在的坐标,这些树桩顺次连成一个凸多边形(该多边形只是形状是凸的,即某些树桩可能会落在多边形边上)。然后是一个整数(m)((1 leq m leq 100)),表示财主下毒的地点数,跟着(m)行,每行两个整数(P_i),(Q_i)((|Pi| leq 10000,|Qi| leq 10000)),即财主下毒地点的坐标,该坐标点可能落在多边形边上或外面,但财主当然不会笨倒在树桩上下毒。
输出格式:
输出文件只有一行,为重新安排后牧羊场的最大面积,答案保留两位小数。如果不可能为成一个新的牧羊场,则输出“ die
”(不包括引号)。
注意:重新围成牧羊场后某段绳子可能会经过下毒的坐标,这是允许的。
思路
区间dp
先讲一些问题简化
对于这题,我们可以发现给出的凸多边形外的点是多余的,因此不用考虑,读入的时候直接过滤。
然后为了dp时的效率,我们预处理出哪些边上有毒药。
然后下面是dp:
[f_{i,j} = max_{k = i + 1}^{j - 1}{{f_{i,j} + SDelta P_iP_kP_j}} (P_iP_j上无毒,Delta P_iP_kP_j内无毒)]
判断 (Delta P_iP_kP_j)内无毒的方法是这样的,可以预处理出(过滤凸多边形外点后)每一条边外侧(即顺时针方向上)的点,然后如果三角形内无毒,那么三条边外面的点加起来之和应该为总点数(已过滤凸多边形外的点)。
CODE
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define MAXN 210
struct Point{
int x,y;
Point(){}
Point(int x,int y):x(x),y(y){}
bool operator < (const Point &a) const{
return (x*a.y-y*a.x)>0;
}
bool operator <= (const Point &a) const{
return (x*a.y-y*a.x)>=0;
}
bool operator != (const Point &a) const{
return x!=a.x||y!=a.y;
}
}pos[MAXN],poison[MAXN];
int f[MAXN][MAXN],outline[MAXN][MAXN];
bool cutted[MAXN][MAXN];
int i,j,k,m,n,x,y,ans,cnt,r;
bool check(int x,int y){
int tmp;
for(int i=2;i<=n+1;i++){
tmp=(pos[i].x-pos[i-1].x)*(y-pos[i-1].y)-(pos[i].y-pos[i-1].y)*(x-pos[i-1].x);
if(tmp<=0){
return false;
}
}
return true;
}
bool check(int a,int b,int c){
Point p1(pos[b].x-pos[a].x,pos[b].y-pos[a].y),p2(poison[c].x-pos[a].x,poison[c].y-pos[a].y);
if(p1.x*p2.y-p1.y*p2.x==0) return true;
return false;
}
int getsize(int p1,int p2,int p3){
return (pos[p2].x*pos[p3].y-pos[p2].y*pos[p3].x-
pos[p1].x*pos[p3].y+pos[p1].y*pos[p3].x+
pos[p1].x*pos[p2].y-pos[p1].y*pos[p2].x);
}
int main(){
freopen("sheep.in","r",stdin);
freopen("sheep.out","w",stdout);
memset(f,0,sizeof(f));
scanf("%d",&n);
for(i=1;i<=n;i++){
scanf("%d%d",&pos[i].x,&pos[i].y);
pos[i].x+=10000,pos[i].y+=10000;
}
for(i=1;i<=n;i++) pos[n+i]=pos[i];
cnt=0;
scanf("%d",&m);
for(i=1;i<=m;i++){
scanf("%d%d",&x,&y);
x+=10000,y+=10000;
if(check(x,y)){
poison[++cnt]=Point(x,y);
}
}
m=cnt;
for(i=1;i<=2*n;i++){
for(j=1;j<=2*n;j++){
for(k=1;k<=m;k++){
if(check(i,j,k)==true&&pos[i]!=poison[k]&&pos[j]!=poison[k]) {
cutted[i][j]=true;
}
if(Point(poison[k].x-pos[i].x,poison[k].y-pos[i].y)<=Point(pos[j].x-pos[i].x,pos[j].y-pos[i].y)) outline[i][j]++;
}
}
}
ans=0;
for(i=3;i<=n+1;i++){
for(j=1;j+i-1<=2*n;j++){
r=j+i-1;
for(k=j+1;k<=r-1;k++){
if(outline[j][k]+outline[k][r]+outline[r][j]==m&&(!cutted[j][k])){
f[j][r]=max(f[j][r],f[j][k]+getsize(j,k,r));
}
}
ans=max(ans,f[j][r]);
}
}
if(ans==0){
printf("die
");
}else{
printf("%.2f
",0.5*ans);
}
return 0;
}
/*
4 //树桩数
2 2
-2 2
-2 -2
2 -2
2 //投毒点数
0 0
1 1
*/
以上是关于可怜的牧羊人的主要内容,如果未能解决你的问题,请参考以下文章