Jack Straws(叉积 + floyd / 并查集)

题目地址

poj1127

判断线段是否相交

ab cd
用叉积的性质判断 a与cd,b与cd, c与ab,d与ab的关系(模板可以去找一下)

1 floyd 更新联通。

把枚举两两线段,判断是否相交,再用floyd去更新,推广出所有线段之间的联通关系。

代码:

#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
 
const int INF = 0x3f3f3f3f;
const double eps = 1e-4;
const int mod = 999911659;
const int N = 1010;

struct Node{
	int x,y;
};

Node sa[N],en[N];
int dp[N][N],fa[N];

int dir(Node x,Node y,Node z){
	int x1 = z.x-x.x,x2 = y.x-x.x;
	int y1 = z.y-x.y,y2 = y.y-x.y;
	return x1*y2-x2*y1;
}

bool on_segment(Node x,Node y,Node z){
	if(z.x >= min(x.x,y.x) && z.x <= max(x.x,y.x) && z.y >= min(x.y,y.y) && z.y <= max(x.y,y.y))
		return true;
	return false;
}

bool segment_judge(Node x,Node y,Node xx,Node yy){
	int d1 = dir(xx,yy,x); // -> 确定 x 在线段xxyy的哪边 
	int d2 = dir(xx,yy,y); // -> 确定 y 在线段xxyy的哪边 
	int d3 = dir(x,y,xx); // -> 确定 xx 在线段xy的哪边 
	int d4 = dir(x,y,yy); // -> 确定 yy 在线段xy的哪边 
	// 同时满足 
	if(((d1 < 0 && d2 > 0) || (d1 > 0 && d2 < 0)) && ((d3 < 0 && d4 > 0) || (d3 > 0 && d4 < 0))) return true;
	if(d1 == 0 && on_segment(xx,yy,x)) return true;
	else if(d2 == 0 && on_segment(xx,yy,y)) return true;
	else if(d3 == 0 && on_segment(x,y,xx)) return true;
	else if(d4 == 0 && on_segment(x,y,yy)) return true;
	else return false;
}

signed main(){
//	IOS;
	#ifdef ddgo
		freopen("C:/Users/asus/Desktop/ddgoin.txt","r",stdin);
	#endif
	
	int n;
	while(cin>>n){
		for(int i=0;i<n;i++){
			int x1,y1,x2,y2; cin>>x1>>y1>>x2>>y2;
			sa[i] = {x1,y1};
			en[i] = {x2,y2};
		}
		
		for(int i=0;i<n;i++)
			for(int j=i;j<n;j++)
				dp[i][j] = dp[j][i] = segment_judge(sa[i],en[i],sa[j],en[j]);
		
		for(int k=0;k<n;k++)
			for(int i=0;i<n;i++)
				for(int j=0;j<n;j++)
					dp[i][j] = dp[i][j] | (dp[i][k] & dp[k][j]);
		
		int a,b;
		while(cin>>a>>b){
			if(a == 0 && b == 0) break;
			cout<<(dp[a-1][b-1]?"CONNECTED":"NOT CONNECTED")<<endl;
		}
	}
    return 0;
}

2:
把枚举两两线段,判断是否相交,相交则放入到一个集合。
最后判断两条线段是否在一个集合中即可

#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
 
const int INF = 0x3f3f3f3f;
const double eps = 1e-4;
const int mod = 999911659;
const int N = 1010;

struct Node{
	int x,y;
};

Node sa[N],en[N];
int dp[N][N],fa[N];

int dir(Node x,Node y,Node z){
	int x1 = z.x-x.x,x2 = y.x-x.x;
	int y1 = z.y-x.y,y2 = y.y-x.y;
	return x1*y2-x2*y1;
}

bool on_segment(Node x,Node y,Node z){
	if(z.x >= min(x.x,y.x) && z.x <= max(x.x,y.x) && z.y >= min(x.y,y.y) && z.y <= max(x.y,y.y))
		return true;
	return false;
}

bool segment_judge(Node x,Node y,Node xx,Node yy){
	int d1 = dir(xx,yy,x); // -> 确定 x 在线段xxyy的哪边 
	int d2 = dir(xx,yy,y); // -> 确定 y 在线段xxyy的哪边 
	int d3 = dir(x,y,xx); // -> 确定 xx 在线段xy的哪边 
	int d4 = dir(x,y,yy); // -> 确定 yy 在线段xy的哪边 
	// 同时满足 
	if(((d1 < 0 && d2 > 0) || (d1 > 0 && d2 < 0)) && ((d3 < 0 && d4 > 0) || (d3 > 0 && d4 < 0))) return true;
	if(d1 == 0 && on_segment(xx,yy,x)) return true;
	else if(d2 == 0 && on_segment(xx,yy,y)) return true;
	else if(d3 == 0 && on_segment(x,y,xx)) return true;
	else if(d4 == 0 && on_segment(x,y,yy)) return true;
	else return false;
}

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

signed main(){
//	IOS;
	#ifdef ddgo
		freopen("C:/Users/asus/Desktop/ddgoin.txt","r",stdin);
	#endif
	
	int n;
	while(cin>>n){
		for(int i=0;i<n;i++){
			int x1,y1,x2,y2; cin>>x1>>y1>>x2>>y2;
			sa[i] = {x1,y1};
			en[i] = {x2,y2};
		}
		for(int i=0;i<=n;i++) fa[i] = i;
		
		for(int i=0;i<n;i++)
			for(int j=i;j<n;j++)
				if(segment_judge(sa[i],en[i],sa[j],en[j]))
					fa[find(i)] = find(j);
		
		int a,b;
		while(cin>>a>>b){
			if(a == 0 && b == 0) break;
			cout<<(find(a-1) == find(b-1)?"CONNECTED":"NOT CONNECTED")<<endl;
		}
	}
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值