usaco 3.4.1 fence4

哇咔咔,终于过了我的第一道计算几何~~

一开始看了题解,没看懂...然后在自己的思维下开始写:

1,判断合法的闭合栅栏,其实就是判断线段两两是否相交(顶点相交不算相交)

2,判断某条线段能否被看到,二分,先从出发点到该线段中点连一条线段(k,kk)(k为看的点,kk为线段中点),看其他线段(设为(p,q))与(k,kk)是否相交,若不相交,则说明线段(p,q)没有遮住该线段,若相交,则继续二分,直到到达精度限制

3,这样写出来后,发现严重超时,开始考虑优化,如果从看的点出发到两个顶点所连线段都与其他某一条线段(设为(p,q))相交,那么线段(p,q)一定遮住该线段,这是可以肯定的。事实证明这是个很强大的优化,加上之后立刻AC。。。

4,经验:对于一些很恶心的题,一开始也许思路比较模糊,但是要逼自己去写,写着写着,思维会慢慢打开...

{
ID:lucky141
PROG:fence4
LANG:PASCAL
}
program fence4;
type
node=record
x,y:real;
end;
var
a:array[1..201] of node;
f:array[1..201] of boolean;
n,i,j,ans:longint;
flag:boolean;
k:node;
function max(p,q:real):real;
begin
if p>q then max:=p
else max:=q;
end;
function min(p,q:real):real;
begin
if p<q then min:=p
else min:=q;
end;
function chaji(p1,p2,p0:node):real;//计算叉积
begin
chaji:=(p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
end;
function check1(p1,q1,p2,q2:node):boolean;//端点相交不算相交
begin
check1:=(max(p1.x,q1.x)>=min(p2.x,q2.x)) and (max(p2.x,q2.x)>=min(p1.x,q1.x))
and (max(p1.y,q1.y)>=min(p2.y,q2.y)) and (max(p2.y,q2.y)>=min(p1.y,q1.y))
and (chaji(p2,q1,p1)*chaji(q1,q2,p1)>0)
and (chaji(p1,q2,p2)*chaji(q2,q1,p2)>0);
end;
function check2(p1,q1,p2,q2:node):boolean;//端点相交算相交
begin
check2:=(max(p1.x,q1.x)>=min(p2.x,q2.x)) and (max(p2.x,q2.x)>=min(p1.x,q1.x))
and (max(p1.y,q1.y)>=min(p2.y,q2.y)) and (max(p2.y,q2.y)>=min(p1.y,q1.y))
and (chaji(p2,q1,p1)*chaji(q1,q2,p1)>=0)
and (chaji(p1,q2,p2)*chaji(q2,q1,p2)>=0);
end;


以上全是计算几何的模板...



function mid(p1,p2:node):node;//取中点
var
cc:node;
begin
cc.x:=(p1.x+p2.x)/2;
cc.y:=(p1.y+p2.y)/2;
mid:=cc;
end;
function endd(p,q:node):boolean;//判断精度
begin
if sqrt(sqr(p.x-q.x)+sqr(p.y-q.y))<0.01 then endd:=true
else endd:=false;
end;
function work(l,r:node):boolean;//判断线段(l,r)能否被看到
var
kk:node;
begin
if endd(l,r) then exit(false);
if check1(k,l,a[j],a[j+1]) and check1(k,r,a[j],a[j+1]) then exit(false);
kk:=mid(l,r);
for j:=1 to n do
if i<>j then
begin
if check2(k,kk,a[j],a[j+1]) then
begin
if not work(l,kk) and not work(kk,r) then exit(false);
end;
end;
exit(true);
end;
begin
assign(input,'fence4.in');
reset(input);
assign(output,'fence4.out');
rewrite(output);
fillchar(a,sizeof(a),0);
readln(n);
readln(k.x,k.y);
for i:=1 to n do
readln(a[i].x,a[i].y);
a[n+1]:=a[1];
for i:=1 to n do
for j:=1 to i-1 do
if check1(a[i],a[i+1],a[j],a[j+1]) then
begin
writeln('NOFENCE');
close(input);
close(output);
halt;
end;
ans:=0;
fillchar(f,sizeof(f),false);
for i:=1 to n do
begin
flag:=true;
f[i]:=work(a[i],a[i+1]);
if f[i] then inc(ans);
end;
writeln(ans);
for i:=1 to n-2 do
if f[i] then writeln(a[i].x:0:0,' ',a[i].y:0:0,' ',a[i+1].x:0:0,' ',a[i+1].y:0:0);
if f[n] then writeln(a[n+1].x:0:0,' ',a[n+1].y:0:0,' ',a[n].x:0:0,' ',a[n].y:0:0);
if f[n-1] then writeln(a[n-1].x:0:0,' ',a[n-1].y:0:0,' ',a[n].x:0:0,' ',a[n].y:0:0);
close(input);
close(output);
end.

转载于:https://www.cnblogs.com/stmq/p/3239262.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值