首页 > ACM题库 > HDU-杭电 > HDU 3151-Cave Crisis[解题报告]HOJ
2014
03-06

HDU 3151-Cave Crisis[解题报告]HOJ

Cave Crisis

问题描述 :

R2D2 was exploring a tunnel when a cave-in suddenly occurred. Oh no, is he trapped?

Robot Roll Call � Cambot…Servo…Gypsy…Croooow
Figure1: Overhead view of the cave crisis from the third example test case.

From an overhead view, we can see all the obstacles (debris) on a two-dimensional Cartesian plane. The tunnel is w cm wide, bounded by the lines y = w/2 and
y = -w/2. R2D2 starts at (0, 0), and has a perfectly circular footprint of radius r. The exit of the tunnel lies to the right of the line x = 1000. Between R2D2 and the exit lie a number of polygonal obstacles.

Is it possible for R2D2 to navigate between the obstacles and make it to the exit?

Robot Roll Call � Cambot…Servo…Gypsy…Croooow

输入:

The input file will contain multiple test cases. Each test case begins with a single line containing an even integer w (2 <= w <= 1000), the width of the tunnel, and an integer N (0 <= N <= 100), the number of obstacles. The next N lines each contain the description of a single obstacle. The ith obstacle is a simple polygon, specified on a single line containing an integer ni (3 <= ni <= 10), the number of vertices, followed by ni pairs of integers, xij and yij (0 <= xij <= 1000 and -w/2 <= yij <= w/2 for j = 1, …, ni ), specifying the coordinates of the vertices in counterclockwise order. Note that obstacles in the input may touch or even overlap. However, you are guaranteed that R2D2’s initial location will not touch or overlap any obstacle. The vertices of each polygon are unique, no two nonconsecutive edges of the polygon intersect (even at their endpoints), and each polygon is guaranteed to have nonzero area. The end-of-input is denoted by an invalid test case with w = N = 0 and should not be processed.

输出:

The input file will contain multiple test cases. Each test case begins with a single line containing an even integer w (2 <= w <= 1000), the width of the tunnel, and an integer N (0 <= N <= 100), the number of obstacles. The next N lines each contain the description of a single obstacle. The ith obstacle is a simple polygon, specified on a single line containing an integer ni (3 <= ni <= 10), the number of vertices, followed by ni pairs of integers, xij and yij (0 <= xij <= 1000 and -w/2 <= yij <= w/2 for j = 1, …, ni ), specifying the coordinates of the vertices in counterclockwise order. Note that obstacles in the input may touch or even overlap. However, you are guaranteed that R2D2’s initial location will not touch or overlap any obstacle. The vertices of each polygon are unique, no two nonconsecutive edges of the polygon intersect (even at their endpoints), and each polygon is guaranteed to have nonzero area. The end-of-input is denoted by an invalid test case with w = N = 0 and should not be processed.

样例输入:

6 2
4 2 -1 4 -1 4 1 2 1
3 3 0 6 -1 6 1
8 2
3 1 -1 4 -1 4 4
3 3 -4 6 1 3 1
10 7
4 0 5 4 2 5 3 4 5
3 4 -5 9 -5 9 0
4 8 -5 11 -5 11 -2 8 -2
3 8 3 16 1 11 5
4 21 -5 23 -3 20 -2 15 -4
3 22 3 26 -1 28 0
3 24 0 29 4 25 3
0 0

样例输出:

1.00
impossible
1.33

#include <stdio.h>
#include <cstring>
#include <algorithm>
#include <math.h>
#include <vector>
using namespace std;
#define INF 1000000000
const double eps = 1e-8;
const double pi = acos(-1.0);

int cmp(double x)
{
	if (fabs(x) < eps) return 0;
	if (x > 0) return 1;
	return -1;
}
inline double sqr(double x){return x*x;}
struct point
{
	double x,y;
	point(){}
	point(double a,double b):x(a),y(b){}
	void input()
	{
		scanf("%lf%lf",&x,&y);
	}
	friend point operator + (const point &a, const point &b)
	{
		return point(a.x+b.x, a.y+b.y);
	}
	friend point operator - (const point &a, const point &b)
	{
		return point(a.x-b.x, a.y-b.y);
	}
	friend bool operator == (const point &a, const point &b)
	{
		return cmp(a.x-b.x)==0 && cmp(a.y-b.y)==0;
	}
	friend point operator * (const point &a, const double &b)
	{
		return point(a.x*b, a.y*b);
	}
	friend point operator * (const double &a, const point &b)
	{
		return point(a*b.x, a*b.y);
	}
	friend point operator / (const point &a, const double &b)
	{
		return point(a.x/b, a.y/b);
	}
	bool operator<(const point& a)const
	{
		if (cmp(x-a.x)!=0) return x<a.x;
		return y<a.y;
	}
	double norm()
	{
		return sqrt(sqr(x) + sqr(y));
	}
};
double det(const point &a, const point &b)
{
	return a.x*b.y-a.y*b.x;
}
double dot(const point &a,const point &b)
{
	return a.x*b.x+a.y*b.y;
}

double dis_point_segment(point p, point s, point t)
{
	if (cmp(dot(p-s, t-s)) < 0) return (p-s).norm();
	if (cmp(dot(p-t, s-t)) < 0) return (p-t).norm();
	return fabs(det(s-p, t-p)) / (s-t).norm();
}

double caldis(point a, point b, point c, point d)
{
	if (cmp(det(a-c, d-c) * det(b-c, d-c)) < 0 && 
		cmp(det(c-a, b-a) * det(d-a, b-a)) < 0) return 0.0;
	double t1 = min(dis_point_segment(a, c, d), dis_point_segment(b, c, d));
	double t2 = min(dis_point_segment(c, a, b), dis_point_segment(d, a, b));
	return min(t1, t2);
}

int W, n;
vector<point> con[110];
double dis[110][110];
int fa[110];

int get_fa(int x)
{
	if (fa[x] == x) return x;
	fa[x] = get_fa(fa[x]);
	return fa[x];
}

void merge(int x,int y)
{
	x=get_fa(x);y=get_fa(y);
	fa[x] = y;
}

bool check(double d)
{
	for (int i=0; i<n+2; i++) fa[i]=i;
	for (int i=0; i<n+2; i++)
	{
		for (int j=i+1; j<n+2; j++)
		if (cmp(dis[i][j] - d)<0)
			merge(i,j);
	}
	int x=get_fa(n), y=get_fa(n+1);
	if (x==y) return false;
	return true;
}

int main()
{
	while(scanf("%d%d",&W,&n)!=EOF)
	{
		if (W==0 && n==0) break;
		double w = W/2.0;
		for (int i=0;i<n;i++)
		{
			int k;
			scanf("%d",&k);
			con[i].clear();
			for (int j=1; j<=k; j++)
			{
				double x,y;
				scanf("%lf%lf",&x,&y);
				con[i].push_back(point(x,y));
			}
			con[i].push_back(con[i][0]);
			for (int j=0; j<i; j++)
			{
				dis[i][j]=INF;
				for (int k=0; k+1<con[i].size(); k++)
				for (int d=0; d+1<con[j].size(); d++)
					dis[i][j]=min(dis[i][j], caldis(con[i][k],con[i][k+1], con[j][d],con[j][d+1]));
				dis[j][i] = dis[i][j];
			}
			dis[i][n] = dis[i][n+1] = INF;

			for (int j=0; j<con[i].size(); j++)
			{
				dis[i][n] = min(dis[i][n], w-con[i][j].y);
				dis[i][n+1] = min(dis[i][n+1], w+con[i][j].y);
			}
			dis[n][i] = dis[i][n];
			dis[n+1][i] = dis[i][n+1];
		}
		dis[n][n+1]=dis[n+1][n] = w * 2.0;
		double L=0.0, r=w, mid;
		for (int i=0; i<n; i++)
		for (int j=0; j+1<con[i].size(); j++)
			r = min(r, dis_point_segment(point(0,0), con[i][j], con[i][j+1]));
		r*=2.0;
		while((r-L)>eps)
		{
			mid=(L+r)/2.0;
			if (check(mid)) L=mid;
			else r=mid;
		}
		if (cmp(L)>0) printf("%.2lf\n",L/2.0);
		else printf("impossible\n");
	}
	return 0;
}

  1. 在方法1里面:

    //遍历所有的边,计算入度
    for(int i=0; i<V; i++)
    {
    degree = 0;
    for (j = adj .begin(); j != adj .end(); ++j)
    {
    degree[*j]++;
    }
    }

    为什么每遍历一条链表,要首先将每个链表头的顶点的入度置为0呢?
    比如顶点5,若在顶点1、2、3、4的链表中出现过顶点5,那么要增加顶点5的入度,但是在遍历顶点5的链表时,又将顶点5的入度置为0了,那之前的从顶点1234到顶点5的边不是都没了吗?

  2. 约瑟夫也用说这么长……很成熟的一个问题了,分治的方法解起来o(n)就可以了,有兴趣可以看看具体数学的第一章,关于约瑟夫问题推导出了一系列的结论,很漂亮