您的位置:首页 > 其它

UVALive 2221 Frontier(计算几何 + DP)

2013-09-24 23:47 381 查看
题目大意:有n个tower,m个monument,要求n个点中找出几个点围成一个凸多边形包含这m个点,使这个多边形周长最小,输出这个周长。

思路:m个点全都要被包含,明显只关系到最外围的点,那么把m个点求凸包,然后考虑如果取某个点为起点顺时针走,那么一个一个点加进去,最后这个点可以和前面的点连接,设中间这个点是k,然后d[ i ][ j ]  = min(d[ i ][ k ] + len(k , j) ),其中k、j这段中m没有点在外面,d[ i ][ j ]表示以 i 为起点,j 为终点顺时针走的最短距离。

先开始一直有个地方不会,就是怎么判断这个线没有点在外面,后来发现,只要做三个点叉积就行了,右手比划一下就行了。

这里还有个坑,那就是如果m == 0,那么需要特判,面积不为0,那么此时是个三角形,有可能出现三个点共线的情况,如果 m 有值,就肯定不会取到三角形三点共线的情况。(看 discuss 看来的。。。 = =)

代码如下:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;

const double INF = 1e9;

const double eps = 1e-8;

struct Point {
double x, y;
Point(){}
Point(double a,double b): x(a),y(b) {}
void read()
{
scanf("%lf%lf",&x,&y);
}
Point operator - (const Point& t) const {
Point tmp;
tmp.x = x - t.x;
tmp.y = y - t.y;
return tmp;
}
Point operator + (const Point& t) const {
Point tmp;
tmp.x = x + t.x;
tmp.y = y + t.y;
return tmp;
}
bool operator == (const Point& t) const {
return fabs(x-t.x) < eps && fabs(y-t.y) < eps;
}
}tow[55],mon[1111<<1];

inline double Cross(Point a, Point b, Point c) {                    // 叉积
return (b.x-a.x)*(c.y-a.y) - (c.x-a.x)*(b.y-a.y);
}
inline double PPdis(Point a, Point b) {                             // 点点距离
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
inline double PLdis(Point p,Point l1,Point l2){                     // 点线距离
return fabs(Cross(p,l1,l2))/PPdis(l1,l2);
}
inline bool same_dir(Point a, Point b) {                            // 向量是否同向
return fabs(a.x*b.y-b.x*a.y) < eps && a.x*b.x > -eps && a.y*b.y > -eps;
}
bool dotOnSeg(Point p, Point s, Point e) {                          // 点是否在线段上
if ( p == s || p == e )     // 看具体情况端点是否合法
return true;
return fabs((p-s).x*(p-e).y - (p-e).y*(p-s).x) < eps &&
(p.x-s.x)*(p.x-e.x)<eps && (p.y-s.y)*(p.y-e.y)<eps;
}
bool Intersect(Point p1, Point p2, Point p3, Point p4, Point& p) {  // 直线相交
double a1, b1, c1, a2, b2, c2, d;
a1 = p1.y - p2.y; b1 = p2.x - p1.x; c1 = p1.x*p2.y - p2.x*p1.y;
a2 = p3.y - p4.y; b2 = p4.x - p3.x; c2 = p3.x*p4.y - p4.x*p3.y;
d = a1*b2 - a2*b1;
if ( fabs(d) < eps ) return false;
p.x = (-c1*b2 + c2*b1) / d;
p.y = (-a1*c2 + a2*c1) / d;
return true;
}
bool cmpyx(Point a, Point b) {
if ( a.y != b.y )
return a.y < b.y;
return a.x < b.x;
}
void Grahamxy(Point *p, int &n) {                                   // 水平序(住:两倍空间)
if ( n < 3 )
return;
int i, m=0, top=1;
sort(p, p+n, cmpyx);
for (i=n; i < 2*n-1; i++)
p[i] = p[2*n-2-i];
for (i=2; i < 2*n-1; i++) {
while ( top > m && Cross(p[top], p[i], p[top-1]) < eps )
top--;
p[++top] = p[i];
if ( i == n-1 ) m = top;
}
n = top;
}

bool is[55][55];

double d[55][55];

int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
for(int i = 0;i<n;i++)
tow[i].read();
for(int i = 0;i<m;i++)
mon[i].read();
double ans = INF;
if(m == 0)
{
for(int i = 0;i<n;i++)
for(int j = i+1;j<n;j++)
for(int k = j+1;k<n;k++)
{
double tmp = Cross(tow[i],tow[j],tow[k]);
if(tmp <= eps && tmp >= -eps) continue;
ans = min(ans,PPdis(tow[i],tow[j]) + PPdis(tow[i],tow[k]) + PPdis(tow[j],tow[k]));
//printf("i = %d,j = %d,k = %d,ans = %f\n",i,j,k,ans);
}
printf("%.2f\n",ans);
continue;
}
int tot = m;
Grahamxy(mon,tot);
//printf("tot = %d\n",tot);
//for(int i = 0;i<tot;i++)
//printf("x = %f,y = %f\n",mon[i].x,mon[i].y);
for(int i = 0;i<n;i++)
for(int j  = 0;j<n;j++)
is[i][j] = 1;
for(int i = 0;i<n;i++)
{
for(int j = 0;j<n;j++)
{
if(i == j) continue;
int ok = 1;
for(int k  = 0;k<tot;k++)
{
if(Cross(tow[i],tow[j],mon[k]) >= 0)
{
ok = 0;
break;
}
}
if(!ok) is[i][j] = 0;
}
is[i][i] = 0;
}
for(int i = 0;i<n;i++)
for(int j = 0;j<n;j++)
d[i][j] = INF;
for(int i = 0;i<n;i++)
for(int j = (i+1)%n;j!=i;j = (j+1)%n)
if(is[i][j])
d[i][j] = PPdis(tow[i],tow[j]);
for(int begin = 0;begin < n;begin ++)
{
for(int end = (begin + 1)%n;;end = (end+1)%n)
{
for(int k = (begin + 1)%n; ;k = (k+1)%n)
{
if(is[k][end])
d[begin][end] = min(d[begin][end],d[begin][k] + d[k][end]);
if(k == end) break;
}
//printf("begin = %d,end = %d,dd = %f\n",begin,end,d[begin][end]);
if(begin == end) break;
}
}
for(int i =0;i<n;i++)
ans = min(ans,d[i][i]);
printf("%.2f\n",ans);
}
return 0;
}

/*

4 0
0 0
0 3
3 0
2 0

*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: