花了连天时间来弄toj 2317.Wall:http://acm.tju.edu.cn/toj/showp2317.html
这是一个赤裸裸的凸包,两天下来,收获不少,慢慢盘点一下。
关于题目本身的分析:
根据题意,用墙把城堡为起来,且周长最短,且墙于城堡至少间隔L。对于一个多边形(凸多边形,凹多边形),如果想要使把它所有点都包含在内的另外一个多边形周长最短,那么必定是该多边形的凸包。那么将凸包的各个边向外移动L的距离,各个边之间就会产生一定距离。如果用半径为L的圆弧连接各边,思考一下,得到这这个图形必然是边长在最短的符合条件的答案。所以,ans=凸包周长+2*PI*L。
对于整个题目而言,第一次作的时候在精度上吃亏了。其实根本就没有必要使用double,int完全足够了。因此在定义PT的时候直接定义为
由于需要按照极角排序,同时还要处理极角相同的问题,那么cmp()应该这么写:
inline
int
crossP(PT a,PT b,PT c)
//
abXac cross product
{
return
(c.x
-
a.x)
*
(b.y
-
a.y)
-
(b.x
-
a.x)
*
(c.y
-
a.y);
}
int
cmp(PT a,PT b)
{
int
re
=
crossP(pt[
0
],a,b);
if
(re
==
0
)
return
dis2(a,pt[
0
])
<
dis2(b,pt[
0
]);
return
re
>
0
;
}
怎么理解sort()里头的cmp()?
我的理解是这样,sort完毕的序列中有a1在a2的前面,那么cmp(a1,a2)始终为true。也不知道准确不准确,请大虾指点~
解决了以上一个小问题,那么这下,我们的Graham-Scan就好写了。
//
Graham-Scan
//
int graham(PT pt[],PT stk[],int n);
//
pt[]是所有点;stk[]返回凸包上的点,逆时针;n是所有点的总数;
//
返回凸包上点的个数。
int
graham(PT pt[],PT stk[],
int
n)
{
int
t,tt
=
0
;
for
(t
=
1
;t
<
n;t
++
)
{
if
(pt[t].y
<
pt[tt].y
||
(pt[t].y
==
pt[tt].y
&&
pt[t].x
<
pt[tt].x))
tt
=
t;
}
//
find the lowest & leftest point
swap(pt[
0
],pt[tt]);
sort(pt
+
1
,pt
+
n,cmp);
for
(t
=
0
;t
<=
2
;t
++
)
stk[t]
=
pt[t];
int
ps
=
2
;
for
(t
=
3
;t
<
n;t
++
)
{
while
(crossP(stk[ps
-
1
],stk[ps],pt[t])
<=
0
)
ps
--
;
stk[
++
ps]
=
pt[t];
}
return
ps
+
1
;
}
That's all.