pku 3185

pku1556

Tuz posted @ 2009年8月28日 00:54 in acm练习 , 796 阅读

计算几何+最短路

思路:把起点,终点,以及门的两个点作为无向图的点建图。两个点可达当且仅当它们可以直线可达,这里用判线相交判断。
代码:

 

#include <stdio.h>
#include <math.h>
#include <string.h>
#define SQR(x) ((x)*(x))
#define oo 9999999999.999
#define eps 1e-16
#define MAXE 120002
#define MAXV 102
#define MAXN 18
typedef struct {  int u; int v; double w; int next;}edge_t;
typedef struct { double x; double y;}pt_t;
edge_t e[MAXE];
pt_t door[MAXN * 4 + 1];
pt_t wall[MAXN * 3 + 1][2];
double dis[MAXV];
int first[MAXV];
int que[MAXV * MAXV];
int has[MAXV];
int head, tail;
int ndoor, nwall;
int tot, st, ed, n;
int dcmp(double x)
{
	if(x < -eps) return -1;
	return x > eps;
}
double cross(double x1, double y1, double x2, double y2)
{
	return x1 * y2 - x2 * y1;
}
int segcross(pt_t a, pt_t b, pt_t c, pt_t d)
{
	int u = dcmp(cross(b.x - a.x, b.y - a.y, c.x - a.x, c.y - a.y) * cross(b.x - a.x, b.y - a.y, d.x - a.x, d.y - a.y));
	int v = dcmp(cross(d.x - c.x, d.y - c.y, a.x - c.x, a.y - c.y) * cross(d.x - c.x, d.y - c.y, b.x - c.x, b.y - c.y));
	return u < 0 && v < 0;
}
void add(int u, int v, double w)
{
	e[++tot].u = u; e[tot].v = v; e[tot].w = w; e[tot].next = first[u]; first[u] = tot;
	e[++tot].u = v; e[tot].v = u; e[tot].w = w; e[tot].next = first[v]; first[v] = tot;
}
void add_door(double x, double y)
{
	++ndoor;
	door[ndoor].x = x;
	door[ndoor].y = y;
}
void add_wall(double x1, double y1, double x2, double y2)
{
	++nwall;
	wall[nwall][0].x = x1;
	wall[nwall][0].y = y1;
	wall[nwall][1].x = x2;
	wall[nwall][1].y = y2;
}
int init()
{
	double x, y1, y2, y3, y4;
	int i;
	scanf("%d", &n);
	if(n == -1) return 0;
	ndoor = 0; nwall = 0;
	add_door(0.0, 5.0);
	for(i = 1;i <= n; i++)
	{
		scanf("%lf %lf %lf %lf %lf", &x, &y1, &y2, &y3, &y4);
		add_door(x, y1);
		add_door(x, y2);
		add_door(x, y3);
		add_door(x, y4);
		add_wall(x, 0.0, x, y1);
		add_wall(x, y2,  x, y3);
		add_wall(x, y4,  x, 10);
	}
	add_door(10.0, 5.0);
	return 1;
}
double dist(pt_t p1, pt_t p2)
{
	return sqrt(SQR(p1.x - p2.x) + SQR(p1.y - p2.y));
}
int check(pt_t a, pt_t b)
{
	int i;
	for(i = 1;i <= nwall; i++) if(segcross(a, b, wall[i][0], wall[i][1])) return 0;
	return 1;
}
void build()
{
	double len;
	int i, j;
	memset(first, -1, sizeof(first));
	tot = -1;
	for(i = 1;i <= ndoor; i++)
	{
		for(j = i + 1;j <= ndoor; j++)
		{
			if(dcmp(fabs(door[i].x - door[j].x)) == 0) continue;
			if(check(door[i], door[j]) == 0) continue;
			len = dist(door[i], door[j]);
			add(i, j, len);
		}
	}
	st = 1; ed = ndoor;
}
void spfa()
{
	int i, j, t;
	for(i = st;i <= ed; i++) dis[i] = oo;
	memset(has, 0, sizeof(has));
	dis[st] = 0.0; has[st] = 1;
	que[0] = st; head = 0; tail = 1;
	while(head < tail)
	{
		i = que[head]; has[i] = 0;
		t = first[i];
		while(t != -1)
		{
			j = e[t].v;
			if(dis[i] + e[t].w + eps < dis[j])
			{
				dis[j] = dis[i] + e[t].w;
				if(has[j] == 0)
				{
					que[tail++] = j;
					has[j] = 1;
				}
			}
			t = e[t].next;
		}
		head++;
	}
}
int main()
{
	while(init())
	{
		build();
		spfa();
		printf("%0.2lf\n", dis[ed]);
	}
	return 0;
}

 

 


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter