51Nod --1951--計算幾何--並查集--難度大

現在有N條公路,編號從1到N,每條公路是一條線段,用兩個端點表示一條公路。如果兩條公路之間有交點那麼這兩條公路可以互通,互通具有傳遞性,比如A和B互通,B和C互通,那麼A就和C互通。

現在給出每條公路的信息以及若干個查詢,查詢某兩條公路之間是否互通。
Input

單組測試數據。 第一行有一個整數N(1 < N < 15),表示公路的數目。 接下來N行,依次給出編號1到N的公路信息,每行給出4個整數xa,ya,xb, yb (-100<=xa,ya,xb, yb<=100),表示公路的兩個端點分別是(xa,ya),(xb,yb)。 接下來有若干個查詢,每行兩個整數u,v(1<=u,v<=N)表示要查詢編號爲u和v之間是否互通。 查詢數目不超過1000。 輸入兩個0表示查詢結束。

Output

對於每一個查詢,如果互通輸出Yes否則輸出No。

Sample Input
樣例輸入1
7
1 6 3 3 
4 6 4 9 
4 5 6 7 
1 4 3 5 
3 5 5 5 
5 2 6 3 
5 4 7 2 
1 4 
1 6 
3 3 
6 7 
2 3 
1 3 
0 0
Sample Output
樣例輸出1
Yes
No
Yes
Yes
No
Yes

思路:1.並查集模板判斷兩個路口是否相通;2.利用計算幾何的知識判斷兩條線段是否相加;

參考判斷模板:判斷兩條線段是否相交:https://blog.csdn.net/queque_heiya/article/details/106187844

注意:開闢的數組空間要大!以及並查集一定要初始化,否則答案全是yes||no.

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath> 
using namespace std;
#define ll long long
const int maxa=1e2+10;
const double pi=1e-8;
const int inf=0x3f3f3f3f;
int n;
struct node{
	int x1,y1;
	int x2,y2;
}a[2*maxa];
int par[maxa];
void init(int n){
	for(int i=0;i<=n;i++)
		par[i]=i;
}
int find(int x){
	if(par[x]==x)	return x;
	else return par[x]=find(par[x]);
}
void unite(int x,int y){
	x=find(x);
    y=find(y);
    if(x==y)	return;
    else	par[x]=y;
}
bool same(int x,int y){
	return find(x)==find(y);
}
bool check(node &a,node &b){
	if(!(min(a.x1,a.x2)<=max(b.x1,b.x2)
	&&min(b.y1,b.y2)<=max(a.y1,a.y2)
	&&min(b.x1,b.x2)<=max(a.x1,a.x2)
	&&min(a.y1,a.y2)<=max(b.y1,b.y2)))	return false;
	double u,v,w,z;
    u=(b.x1-a.x1)*(a.y2-a.y1)-(a.x2-a.x1)*(b.y1-a.y1);
    v=(b.x2-a.x1)*(a.y2-a.y1)-(a.x2-a.x1)*(b.y2-a.y1);
    w=(a.x1-b.x1)*(b.y2-b.y1)-(b.x2-b.x1)*(a.y1-b.y1);
    z=(a.x2-b.x1)*(b.y2-b.y1)-(b.x2-b.x1)*(a.y2-b.y1);
    return (u*v<=pi&&w*z<=pi);
}
int main(){
	while(~scanf("%d",&n)){
		init(n); 
		for(int i=1;i<=n;i++)
			scanf("%d%d%d%d",&a[i].x1,&a[i].y1,&a[i].x2,&a[i].y2);
		//並查集判斷
		for(int i=1;i<=n;i++)
			for(int j=i+1;j<=n;j++)//判斷a[i]與a[j]是否連通 
				if(check(a[i],a[j])) unite(i,j);
		int e1,e2;
		while(scanf("%d%d",&e1,&e2)&&(e1+e2)){
			if(same(e1,e2))	printf("Yes\n");
			else printf("No\n");
		} 
	}
	return 0;
}
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath> 
using namespace std;
#define ll long long
const int maxa=1e2+10;
const double pi=0.00000001;
const int inf=0x3f3f3f3f;
int n;
struct nodea{
	int x,y;
}a[maxa];
struct nodeb{
	int x,y;
}b[maxa];
int par[maxa];
int rank[maxa];
void init(int n){
	for(int i=0;i<=n;i++)
		par[i]=i,rank[i]=1;
}
int find(int x){
	if(par[x]==x)	return x;
	else return par[x]=find(par[x]);
}
void unite(int x,int y){
	x=find(x);
    y=find(y);
    if(x==y)	return;
    if(rank[x]<rank[y])	par[x]=y;
    else{	
		par[y]=x;
		if(rank[x]==rank[y])	rank[x]++;
	}
}
bool same(int x,int y){
	return find(x)==find(y);
}
bool check(nodea a,nodeb b,nodea c,nodeb d){
    if(!(min(a.x,b.x)<=max(c.x,d.x)
	&&min(c.y,d.y)<=max(a.y,b.y)
	&&min(c.x,d.x)<=max(a.x,b.x)
	&&min(a.y,b.y)<=max(c.y,d.y)))	return false; 
    double u,v,w,z;
    u=(c.x-a.x)*(b.y-a.y)-(b.x-a.x)*(c.y-a.y);
    v=(d.x-a.x)*(b.y-a.y)-(b.x-a.x)*(d.y-a.y);
    w=(a.x-c.x)*(d.y-c.y)-(d.x-c.x)*(a.y-c.y);
    z=(b.x-c.x)*(d.y-c.y)-(d.x-c.x)*(b.y-c.y);
    return (u*v<=pi&&w*z<=pi);
}
int main(){
	while(~scanf("%d",&n)){
		init(n);
		for(int i=1;i<=n;i++)
			scanf("%d%d%d%d",&a[i].x,&a[i].y,&b[i].x,&b[i].y);
		//並查集判斷
		for(int i=1;i<=n;i++)
			for(int j=i+1;j<=n;j++)//判斷a[i]與a[j]是否連通 
				if(check(a[i],b[i],a[j],b[j])) unite(i,j);
		int e1,e2;
		while(scanf("%d%d",&e1,&e2)&&(e1+e2)){
			if(same(e1,e2))	printf("Yes\n");
			else printf("No\n");
		} 
	}
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章