(intermediate) 平面区域 UVA Art of War

The Warring States Period (473-22l BC) refers to the centuries of turmoil following the Spring and Autumn Period. China was divided into many little kingdoms that were constantly fighting with each other. Unlike in previous ages, when chivalry played an important role in battles and the states fought mostly for balance of power or to resolve disputes, in this period the aim of battle was to conquer and completely annihilate the other states. Eventually seven states, known as the ``Seven Great Powers'' rose to prominence: Qi, Chu, Yan, Han, Zhao, Wei, and Qin. After numerous alliances and counter-alliances, Qin defeated all the other states one by one, putting an end to the Warring States Period.

You are given a map that shows the position of the capital for each state, and the borders between the states as a series of line segments. Your job is to determine which states were fighting with each other. This is pretty easy to determine - if two states had a common border, then they were fighting.

Input 

The input contains several bloks of test cases. Each case begins with a line containing two integers: the numberl$ \le$n$ \le$600 of states, and the number l$ \le$m$ \le$4000 of border segments. The next n lines describe the coordinates of capitals, there are two integers in each line. The nextm, lines after that describe the m, border segments. Each line contains four integers. xl, yl, x2 and y2, meaning that there is a border segment from(xl, yl) to (x2, y2). (It is not given in the input what the two states on the two sides of the border are, but it can be deduced from the way the borders go.)

Each state is enclosed by a continuous borderline. The states are surrounded by an infinite wasteland, thus a border segment either separates two states, or a state from the wasteland. It is not possible that the same state is on both sides of a border segment, or the wasteland is on both sides of a border segment. There is exactly one capital in each state, and there is no capital in the wasteland. The border segments do not cross each other, they can meet only at the end points.

The input is terminated by a block with n = m =O.

Output 

For each test case, you have to output n lines that describe the enemies of then states (recall that if two states share a border, then they are enemies). Each line begins with an integer, the numberx of enemies the given state has. This number is followed byx numbers identifying the enemies of the state. These numbers are between l andn and number l refers to the first capital appearing in the input, numbern refers to the last.

Sample Input 

4 12
3 2
11 8
12 17
1 19
0 0 10 0
10 0 20 0
20 0 20 10
20 10 20 20
20 20 10 20
10 20 0 20
0 20 0 10
0 10 0 0
10 0 10 10
0 10 10 10
20 10 10 10
10 20 10 10
4 16
170 13
24 88
152 49
1 10 130
60 60 140 60
140 60 140 140
140 140 60 140
60 140 60 60
0 0 200 0
200 0 200 200
200 200 0 200
0 200 0 0
40 40 160 40
160 40 160 160
160 160 40 160
40 160 40 40
20 20 180 20
180 20 180 180
180 180 20 180
20 180 20 20
0 0

Sample Output 

2 2 4
2 1 3
2 2 4
2 1 3
1 2
2 1 3
2 2 4
1 3


题意:给出m条只能在端点处相交的线段,围出了n个有限的封闭区间和一些无限的区域。求出有限封闭区间之间是否相邻。拥有公共边的叫做相邻。注意一个多边形在另一个多边形内,并且没有其他的多边形套在他们之间,那么他们也是相邻的。


思路:我们用卷包裹算法把平面区域求出来。这个算法其实我有些地方不是很理解的。。。先用着吧。lrj写的。然后怎么判断区域是否相邻呢?我们先把所有的区域按面积从小到大排序,然后从最小的多边形开始找第一个把它包围起来的多边形,此时这两个区域相邻,跳出循环,在找下一个。最后我们两两判断两个多边形是否有重复的边,因为这个题目里面说了线段只能在端点处相交,所以只要判断两条线是否平行且两个端点相同。就可以了。最后输出答案就行了。总体的思路就是这样子的。


代码:

#include<iostream>
#include<cstdio>
#include<string.h>
#include<math.h>
#include<string>
#include<cassert>
#include<set>
#include<cstring>
#include<map>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
#define mp make_pair
#define eps 1e-11
const double inf = 1e16;
const double PI = acos(-1.0);

struct Point
{
	Point(const Point&p) { x = p.x , y = p.y; }
	Point (double xx=0,double yy=0) : x(xx) , y(yy) { }
	double x;
	double y;
};



typedef Point Vector;
typedef vector<Point> Polygon;

Vector operator+(Vector  v1,Vector  v2) { return Vector(v1.x+v2.x,v1.y+v2.y); }
Vector operator-(Vector  v1,Vector  v2) { return Vector(v1.x-v2.x,v1.y-v2.y); }
Vector operator*(Vector  v, double p) { return Vector(v.x*p,v.y*p); }
Vector operator/(Vector  v,double p) { return Vector(v.x/p,v.y/p); }

int dcmp(double x)
{
	if (fabs(x) < eps) return 0;
	return x < 0 ? -1 : 1;
}
bool operator < (Point  a,Point  b) { return dcmp(a.x-b.x)<0 || dcmp(a.x-b.x)==0 && dcmp(a.y-b.y)<0; }
bool operator==(const Point & a,const Point & b)
{
	return dcmp(a.x-b.x)==0 && dcmp(a.y-b.y)==0;
}

bool operator!=(const Point& a,const Point& b) { return !(a==b); }

inline double toRad(double x) { return x * PI/180; }
inline double toDegreed(double rad) { return rad*180/PI; }
double Dot(Vector  A,Vector  B) { return A.x*B.x+A.y*B.y; }
double Length(Vector  A) { return sqrt(Dot(A,A)); }
double Angle(Vector A,Vector B)
{
	double cosine = Dot(A,B)/Length(A)/Length(B);
	if (dcmp(cosine-1.0)==0) return 0;
	return acos(cosine);
}
double Cross(Vector A,Vector B) { return A.x*B.y-A.y*B.x; }
double Area2(Point a,Point b,Point c) {  return Cross(b-a,c-a); }
double PolyArea(Polygon poly)
{
	int n = poly.size();
	double ret = 0;
	for (int i = 1 ; i < n-1 ; ++i)
		ret += Cross(poly[i]-poly[0],poly[i+1]-poly[0]);
	return ret/2;
}

//旋转
Vector Rotate(Vector A,double rad)
{
	return Vector(A.x*cos(rad)-A.y*sin(rad),A.x*sin(rad)+A.y*cos(rad));
}

//单位法线
Vector Normal(Vector A) { double L = Length(A); return Vector(-A.y/L,A.x/L); }

//点和直线
Point GetLineIntersection(Point P,Vector v,Point Q,Vector w)
{
	Vector u = P-Q;
	double t = Cross(w,u) / Cross(v,w);
	return P+v*t;
}

double DistanceToLine(Point P,Point A,Point B)
{
	Vector v1 = B-A , v2 = P-A;
	return fabs(Cross(v1,v2))/Length(v1);
}
double DistanceToSegment(Point P,Point A,Point B)
{
	if (A==B) return Length(P-A);
	Vector v1 = B-A , v2 = P-A , v3 = P-B;
	if (dcmp(Dot(v1,v2)) < 0) return Length(v2);
	else if (dcmp(Dot(v1,v3)) > 0) return Length(v3);
	else return fabs(Cross(v1,v2))/Length(v1);
}
//点在直线上的投影
Point GetLineProjection(Point P,Point A,Point B)
{
	Vector v = B-A;
	return A+v*(Dot(v,P-A)/Dot(v,v));
}
//线段相交(不包括端点)
bool SegmentProperIntersection(Point a1,Point a2,Point b1,Point b2)
{
	double c1 = Cross(a2-a1,b1-a1) , c2 = Cross(a2-a1,b2-a1) ,
		c3 = Cross(b2-b1,a1-b1) , c4 = Cross(b2-b1,a2-b1);
	return dcmp(c1)*dcmp(c2) < 0 && dcmp(c3)*dcmp(c4)<0;
}

//点在线段上(不包括端点)
bool OnSegment(Point p,Point a,Point b)
{
	return dcmp(Cross(a-p,b-p))==0 && dcmp(Dot(a-p,b-p)) < 0;
}

//点在线上
bool OnLine(Point p,Point a,Point b)
{
	if (p==a || p==b) return true;
	return dcmp(Cross(a-p,b-p))==0;
}

//线段相交(包括端点)
bool SegmentIntersection(Point a1,Point a2,Point b1,Point b2)
{
	if (SegmentProperIntersection(a1,a2,b1,b2)) return true;
	if (OnSegment(a1,b1,b2) || OnSegment(a2,b1,b2)) return true;
	if (OnSegment(b1,a1,a2) || OnSegment(b2,a1,a2)) return true;
	if (a1==b1 || a1==b2 || a2==b1 || a2==b2) return true;
	return false;
}

//点在多边形内:0:外部 1:内部 -1:线上 -2:在顶点
int isPointInPolygon(Point a,Polygon p)
{
	int wn = 0;
	int n = p.size();
	for (int i = 0 ; i < n ; ++i) {
		if (a==p[i]) return -2; //点重合
		if (OnSegment(a,p[i],p[(i+1)%n])) return -1;
		int k = dcmp(Cross(p[(i+1)%n]-p[i],a-p[i]));
		int d1 = dcmp(p[i].y-a.y);
		int d2 = dcmp(p[(i+1)%n].y-a.y);
		if (k > 0 && d1<=0 && d2>0) ++wn;
		if (k<0 && d2<=0 && d1>0) --wn;
	}
	if (wn!=0) return 1;   //内部
	return 0;                 //外部
}


Polygon ToPolygon(Point* p, int n)
{
	Polygon ret;
	for (int i = 0; i < n; ++i) ret.push_back(p[i]);
	return ret;
}

Polygon simplify(const Polygon& poly)
{
	Polygon ans;
	int n = poly.size();
	for (int i = 0; i < n; ++i)
	{
		Point a = poly[i];
		Point b = poly[(i + 1) % n];
		Point c = poly[(i + 2) % n];
		if (dcmp(Cross(a - b, c - b)) != 0) ans.push_back(b);
	}
	return ans;
}
//--------------------------------------------------------------------------------------------
//直线和直线
struct Line
{
	Point P;				//直线上任意一点
	Vector v;				// 方向向量。它的左边就是对应的半平面
	double ang;			//极角
	Line() { }
	Line(Point P,Vector v)
	{
		this->P = P ; this->v = v;
		ang = atan2(v.y,v.x);
	}
	bool operator < (const Line& L) const { return ang < L.ang; } //排序用的比较运算符
	Point point(double t) { return v*t+P; }
};

//点p在有向直线L的左边(线上不算)
bool OnLeft(Line L , Point p) { return Cross(L.v,p-L.P) > 0; }

//二直线交点。假定交点唯一存在
Point GetIntersection(Line a,Line b)
{
	Vector u = a.P-b.P;
	double t = Cross(b.v,u) / Cross(a.v,b.v);
	return a.P+a.v*t;
}


//--------------------------------------------
//与圆相关
struct Circle
{
	Circle() { }
	Point c;
	double r;
	Circle(Point c, double r) : c(c) , r(r) { }
	Point point (double a) { return Point(c.x+cos(a)*r,c.y+sin(a)*r); }
};

int getLineCircleIntersection(Line L,Circle C,double &t1,double &t2,vector<Point>& sol)
{
	double a = L.v.x , b = L.P.x-C.c.x , c= L.v.y, d = L.P.y-C.c.y;
	double e = a*a+c*c , f = 2*(a*b+c*d) , g = b*b+d*d-C.r*C.r;
	double delta = f*f-4*e*g;				//判别式
	if (dcmp(delta) < 0) return 0;		//相离
	if (dcmp(delta)==0) {                   //相切
		t1 = t2 = -f/(2*e);
		sol.push_back(L.point(t1));
		return 1;
	}
	//相交
	t1 = (-f-sqrt(delta)) / (2*e); sol.push_back(L.point(t1));
	t2 = (-f+sqrt(delta)) / (2*e); sol.push_back(L.point(t2));
	return 2;
}

double angle(Vector v) { return atan2(v.y,v.x); }

int getCircleCircleIntersection(Circle C1,Circle C2,vector<Point>& sol)
{
	double d = Length(C1.c-C2.c);
	if (dcmp(d)==0) {
		if (dcmp(C1.r-C2.r)==0) return -1;			//两圆重合
		return 0;
	}
	if (dcmp(C1.r+C2.r-d) < 0) return 0;
	if (dcmp(fabs(C1.r-C2.r)-d) > 0) return 0;

	double a = angle(C2.c-C1.c);
	double da = acos((C1.r*C1.r+d*d-C2.r*C2.r)/(2*C1.r*d));			//向量C1C2的极角
	//C1C2到C1P1的角
	Point p1 = C1.point(a-da) , p2 = C1.point(a+da);
	sol.push_back(p1);
	if (p1==p2) return 1;
	sol.push_back(p2);
	return 2;
}

//过点p到圆C的切线。v[i]是第i条切线的向量。返回切线条数
int getTangents(Point p,Circle C,Vector* v)
{
	Vector u= C.c-p;
	double dist = Length(u);
	if (dcmp(dist-C.r)<0) return 0;
	else if (dcmp(dist-C.r)==0) {
		v[0] = Rotate(u,PI/2);
		return 1;
	} else {
		double ang = asin(C.r/dist);
		v[0] = Rotate(u,-ang);
		v[1] = Rotate(u,+ang);
		return 2;
	}
}

int getTangents(Circle A,Circle B,Point* a, Point* b)
{
	int cnt = 0;
	if (dcmp(A.r-B.r)<0) { swap(A,B); swap(a,b); }
	double d2 = Dot(A.c-B.c,A.c-B.c);
	double rdiff = A.r-B.r;
	double rsum = A.r+B.r;
	if (dcmp(d2-rdiff*rdiff) < 0) return 0;			//内含

	double base = atan2(B.c.y-A.c.y,B.c.x-A.c.x);
	if (dcmp(d2)==0 && dcmp(A.r-B.r)==0) return -1;	//无限多条切线
	if (dcmp(d2-rdiff*rdiff)==0) {                       //内切,1条切线
		a[cnt] = A.point(base);
		b[cnt] = B.point(base);
		++cnt;
		return 1;
	}
	//有外切共线
	double ang = acos((A.r-B.r)/sqrt(d2));
	a[cnt] = A.point(base+ang); b[cnt] = B.point(base+ang); ++cnt;
	a[cnt] = A.point(base-ang); b[cnt] = B.point(base-ang); ++cnt;
	if (dcmp(d2-rsum*rsum)==0) {                  //一条内公切线
		a[cnt] = A.point(base);
		b[cnt] = B.point(PI+base);
		++cnt;
	} else if (dcmp(d2-rsum*rsum)>0) {           //两条公切线
		double ang = acos((A.r+B.r)/sqrt(d2));
		a[cnt] = A.point(base+ang); b[cnt] = B.point(PI+base+ang); ++cnt;
		a[cnt] = A.point(base-ang); b[cnt] = B.point(PI+base-ang); ++cnt;
	}
	return cnt;
}

//点p和圆的关系: 0:在圆上 1:在圆外 -1:在圆内
int PointCircleRelation(Point p,Circle c)
{
	return dcmp(Dot(p-c.c,p-c.c)-c.r*c.r);
}

//A在B内
bool InCircle(Circle A,Circle B)
{
	if (dcmp(A.r-B.r)>0) return false;
	double d2 = Dot(A.c-B.c,A.c-B.c);
	double rdiff = A.r-B.r;
	double rsum = A.r+B.r;
	if (dcmp(d2-rdiff*rdiff) <= 0) return true;			//内含或内切或重合
	return false;
}

Polygon PolyCircleIntersection(Polygon p,Circle c)
{
	int n = p.size();
	p.push_back(p[0]);
	Polygon ret;
	for (int i = 0; i < n; ++i) {
		double t1 , t2;
		Polygon tmp;
		Line L = Line(p[i],p[i+1]-p[i]);
		getLineCircleIntersection(L,c,t1,t2,tmp);
		if (dcmp(t1)>=0 && dcmp(t1-1)<=0)
			ret.push_back(L.P+L.v*t1);
		if (dcmp(t1-t2)==0) continue;
		if (dcmp(t2)>=0 && dcmp(t2-1)<=0)
			ret.push_back(L.P+L.v*t2);
	}
	return ret;
}

//圆在多边形内,包括相切
bool CircleInPoly(Polygon p,Circle c)
{
	int n = p.size();
	if (isPointInPolygon(c.c,p)==0) return false;
	for (int i = 0; i < n; ++i) {
		double dist = DistanceToLine(c.c,p[i],p[i+1]);
		if (dcmp(dist-c.r)<0) return false;
	}
	return true;
}

//----------------------------------------------------------------------------
//与球相关的转化
//角度转换为弧度
double torad(double deg) { return deg/180*PI; }

//经纬度(角度)转化为空间坐标
void get_coord(double R,double lat,double lng,double& x,double& y,double& z)
{
	lat = torad(lat);
	lng = torad(lng);
	x = R*cos(lat)*cos(lng);
	y = R*cos(lat)*sin(lng);
	z = R*sin(lat);
}

//-----------------------------------------------------------------------
//几何算法:
//凸包:O(nlogn) 得到的凸包逆时针
Polygon ConvexHull(Polygon p, Polygon ch)
{
	int n = p.size();
	sort(p.begin(),p.begin()+n);
	int m = 0;
	for (int i = 0 ; i < n ; ++i) {
		while (m>1 && dcmp(Cross(ch[m - 1] - ch[m - 2], p[i] - ch[m - 2])) <= 0) { ch.pop_back(); --m; 	}
		ch.push_back(p[i]); ++m;
	}
	int k = m;
	for (int i = n-2 ; i >= 0 ; --i) {
		while (m > k && dcmp(Cross(ch[m - 1] - ch[m - 2], p[i] - ch[m - 2])) <= 0) { ch.pop_back();  --m; }
		ch.push_back(p[i]);
		++m;
	}
	if (n > 1) ch.pop_back();
	return ch;
}

//半平面交:(OnLeft>改成=变成最后的半平面可以是一条直线)
Polygon& HalfplaneIntersection(Line* L,int n,Polygon& poly)
{
	sort(L,L+n);						     //按极角排序

	int first , last;					   	 //双端队列的第一个元素和最后一个元素的下表
	Point *p = new Point[n];		    //p[i]为q[i]和q[i+1]的交点
	Line *q = new Line[n];		   //双端队列
	q[first=last=0] = L[0];			  //双端队列初始化为只有一个半平面L[0]
	for (int i = 1 ; i < n ; ++i) {
		while (first < last && !OnLeft(L[i],p[last-1])) --last;
		while (first < last && !OnLeft(L[i],p[first])) ++first;
		q[++last] = L[i];
		if (dcmp(Cross(q[last].v,q[last-1].v))==0) {
			//两向量平行且同向,取内侧的一个
			--last;
			if (OnLeft(q[last],L[i].P)) q[last] = L[i];
		}
		if (first < last) p[last-1] = GetIntersection(q[last-1],q[last]);
	}
	while (first < last && !OnLeft(q[first],p[last-1])) --last;
	//删除无用平面(*)
	if (last - first <=1 ) { delete [] p; delete [] q; return poly; }                   //空集(**)
	p[last] = GetIntersection(q[last],q[first]);		//计算首尾两个半平面的交点

	//从deque复制到输出中
	for (int i = first ; i <= last ; ++i) poly.push_back(p[i]);
	delete [] p; delete[] q;
	return poly;
}

bool OnLine(Point p,Line L)
{
	Vector v = p-L.P;
	return dcmp(Cross(v,L.v))==0;
}
//旋转卡壳:
pair<double,double> RotateCalipers(Point* hull,int n)
{
	hull[n] = hull[0];
	Line L1, L2, L3, L4;
	int q=0, w=0, e=0, r=0;
	for (int i = 0 ; i < n ; ++i) {
		if (dcmp(hull[i].y-hull[q].y)<0) q = i;
		if (dcmp(hull[i].x-hull[w].x)<0) w = i;
		if (dcmp(hull[i].y-hull[e].y)>0) e = i;
		if (dcmp(hull[i].x-hull[r].x)>0) r = i;
	}
	L1 = Line(hull[q],Vector(1,0));
	L2 = Line(hull[w],Vector(0,-1));
	L3 = Line(hull[e],Vector(-1,0));
	L4 = Line(hull[r],Vector(0,1));
	double sum = 0;
	double ansA = inf , ansC = inf;
	while (dcmp(sum-PI/2)<0) {
		double ang = Angle(hull[q+1]-hull[q],L1.v);
		ang = min(ang,Angle(hull[w+1]-hull[w],L2.v));
		ang = min(ang,Angle(hull[e+1]-hull[e],L3.v));
		ang = min(ang,Angle(hull[r+1]-hull[r],L4.v));
		sum += ang;
		L1.v = Rotate(L1.v,ang);
		L2.v = Rotate(L2.v,ang);
		L3.v = Rotate(L3.v,ang);
		L4.v = Rotate(L4.v,ang);
		if (dcmp(ang-Angle(hull[q+1]-hull[q],L1.v))==0) { L1.P = hull[q+1]; q = (q+1)%n; }
		if (dcmp(ang-Angle(hull[w+1]-hull[w],L2.v))==0) { L2.P = hull[w+1]; w = (w+1)%n; }
		if (dcmp(ang-Angle(hull[e+1]-hull[e],L3.v))==0) { L3.P = hull[e+1]; e = (e+1)%n; }
		if (dcmp(ang-Angle(hull[r+1]-hull[r],L4.v))==0) { L4.P = hull[r+1]; r = (r+1)%n; }
		double A = DistanceToLine(L1.P,L3.P,L3.P+L3.v*Length(L1.P-L3.P));
		double B = DistanceToLine(L2.P,L4.P,L4.P+L4.v*Length(L2.P-L4.P));
		ansA = min(ansA,A*B);
		ansC = min(ansC,A+B);
	}
	ansC *= 2;
	return mp(ansA,ansC);
}
//-----------------------------------------------------------------------
const int maxn = 4000 + 10;
struct Edge
{
	int from, to;
	double ang;
	Edge(int f, int t, double a)
		:from(f), to(t), ang(a) { }
};
struct PSLG
{
	int n, m, face_cnt;
	double x[maxn], y[maxn];
	vector<Edge> edges;
	vector<int> G[maxn];
	int vis[maxn * 2];
	int left[maxn * 2];
	int prev[maxn * 2];

	vector<Polygon> faces;
	double area[maxn];

	void init(int n)
	{
		this->n = n;
		for (int i = 0; i < n; ++i) G[i].clear();
		edges.clear();
		faces.clear();
	}

	double getAngle(int from, int to)
	{
		return atan2(y[to] - y[from], x[to] - x[from]);
	}

	void AddEdge(int from, int to)
	{
		edges.push_back(Edge(from, to, getAngle(from, to)));
		edges.push_back(Edge(to, from, getAngle(to, from)));
		m = edges.size();
		G[from].push_back(m - 2);
		G[to].push_back(m - 1);
	}

	void Build()
	{
		for (int u = 0; u < n; ++u)
		{
			int d = G[u].size();
			for (int i = 0; i < d; ++i)
			for (int j = i + 1; j < d; ++j)
			if (edges[G[u][i]].ang>edges[G[u][j]].ang) swap(G[u][i], G[u][j]);
			for (int i = 0; i < d; ++i)
				prev[G[u][(i + 1) % d]] = G[u][i];
		}

		memset(vis, 0, sizeof(vis));
		face_cnt = 0;
		for (int u = 0; u < n; ++u)
		for (int i = 0; i < G[u].size(); ++i) {
			int e = G[u][i];
			if (!vis[e]) {
				Polygon poly;
				for (;;) {
					vis[e] = 1; left[e] = face_cnt;
					int from = edges[e].from;
					poly.push_back(Point(x[from], y[from]));
					e = prev[e ^ 1];
					if (e == G[u][i]) break;
					assert(vis[e] == 0);
				}
				faces.push_back(poly);
				++face_cnt;
			}
		}
		for (int i = 0; i < faces.size();)
		{
			area[i] = PolyArea(faces[i]);
			if (area[i] <= 0) {
				--face_cnt;
				faces.erase(faces.begin() + i);
			}
			else ++i;
		}
		for (int i = 0; i < face_cnt; ++i)
		{
			int k = i;
			for (int j = i + 1; j < face_cnt; ++j)
			{
				if (area[k] > area[j]) k = j;
			}
			if (k == i) continue;
			swap(area[k], area[i]);
			swap(faces[i], faces[k]);
		}
	}
};

//-----------------------------------------
vector<Point> p;
Point cap[maxn];
int face[maxn];
vector<Point> V;
int n, m;

int ID(const Point&a)
{
	return lower_bound(V.begin(), V.end(), a) - V.begin();
}


void input()
{
	for (int i = 0; i < n; ++i) scanf("%lf%lf", &cap[i].x, &cap[i].y);
	for (int i = 0; i < 2*m; ++i)
	{
		Point a;
		scanf("%lf%lf", &a.x, &a.y);
		V.push_back(a);
		p.push_back(a);
	}
	sort(V.begin(), V.end());
	V.erase(unique(V.begin(),V.end()),V.end());
}

int findface(const Point&p, const PSLG&pg)
{
	const vector<Polygon>& py = pg.faces;
	int ret = -1; double S = inf;
	for (int i = 0; i < py.size(); ++i) if (dcmp(pg.area[i])>0)
	{
		if (isPointInPolygon(p, py[i]))
		{
			if (S > pg.area[i])
			{
				ret = i;
				S = pg.area[i];
			}
		}
	}
	return ret;
}

//p1在p2里面
bool PolygonInPolygon(const Polygon&p1, const Polygon&p2)
{
	int n = p1.size(), m = p2.size();
	for (int i = 0; i < n;++i)
	if (isPointInPolygon(p1[i], p2) == 0) return false;
	return true;
}

int face_to_cap[maxn];
int adj[610][610];
int cnt[610];

bool sameboarder(const Polygon&p1, const Polygon&p2)
{
	int n = p1.size(), m = p2.size();
	for (int i = 0; i < n; ++i)
	{
		Point a = p1[i], b = p1[(i + 1) % n];
		Vector v1 = b - a;
		for (int j = 0; j < m; ++j)
		{
			Point c = p2[j], d = p2[(j + 1) % m];
			Vector v2 = d - c;
			if (Cross(v1, v2) != 0) continue;
			if (a == c&&b == d) return true;
			if (a == d&&b == c) return true;
		}
	}
	return false;
}

void solve()
{
	PSLG pg; pg.init(V.size());
	for (int i = 0; i < p.size(); i += 2)
	{
		int u = ID(p[i]), v = ID(p[i + 1]);
		pg.x[u] = p[i].x, pg.y[u] = p[i].y;
		pg.x[v] = p[i+1].x, pg.y[v] = p[i+1].y;
		pg.AddEdge(u, v);
	}
	pg.Build();
	for (int i = 0; i < n; ++i)
	{
		face[i] = findface(cap[i], pg);
		face_to_cap[face[i]] = i;
	}
	memset(adj, 0, sizeof(adj));
	memset(cnt, 0, sizeof(cnt));
	for (int i = 0; i < pg.faces.size(); ++i)
	{
		for (int j = i + 1; j < pg.faces.size(); ++j)
		{
			if (PolygonInPolygon(pg.faces[i], pg.faces[j]))
			{
				int u = face_to_cap[i], v = face_to_cap[j];
				if (!adj[u][v]) ++cnt[u];
				if (!adj[v][u]) ++cnt[v];
				adj[u][v] = adj[v][u] = true;
				break;
			}
		}
	}
	for (int i = 0; i < pg.faces.size(); ++i)
	{
		for (int j = i + 1; j < pg.faces.size(); ++j)
		{
			if (sameboarder(pg.faces[i], pg.faces[j]))
			{
				int u = face_to_cap[i], v = face_to_cap[j];
				if (!adj[u][v]) ++cnt[u];
				if (!adj[v][u]) ++cnt[v];
				adj[u][v] = adj[v][u] = true;
			}
		}
	}
	for (int i = 0; i < n; ++i)
	{
		printf("%d", cnt[i]);
		for (int j = 0; j < n&&cnt[i]; ++j) if (adj[i][j])
		{
			printf(" %d", j+1);
			--cnt[i];
		}
		printf("\n");
	}
}

int main()
{
    freopen("in.txt","r",stdin);
	while (scanf("%d%d", &n, &m) == 2)
	{
		p.clear(); V.clear();
		input();
		solve();
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值