codeforces1163C2 2000分计算几何

题目传送门

题意:

二维平面内n个不同位置的横纵坐标都为整数的点,假如存在多于一个点位于同一条直线,那么就画出这条直线。询问有多少对直线相交。

数据范围:n <= 1000 , -10000 <= 横纵坐标 <= 10000。

题解:

自定义:垂直于y轴的线叫横线。垂直于x轴的线叫竖线。其他直线叫斜线。

答案由4部分累加得来:

(1)所有的横线与所有的竖线两两相交。

(2)所有的斜线与所有的横线两两相交。

(3)所有的斜线与所有的竖线两两相交。

(4)所有不平行的斜线两两相交。

最后一部分是斜线之间的计算:首先建立一个map,判定同斜率且同截距是否出现过。注意斜率相同的直线不相交。

关于斜率和截距的存储方式,可以用double,也可以用最简分数,这两种我都试了试并且都可以过,其实我觉得由于精度的关系double不是很稳,但它确实是过了,并且比最简分数要快。

感受:

这道题题意是非常的简单,我就误以为做法很简单,第一反应还在想这题为什么会有2000分。结果写着写着发现确实是有点麻烦。我认为与其称它是计算几何的题目,不如称为模拟题。因为我计算几何一点不会,其实是通过分类讨论把它模拟出来的。

代码1(double存储斜线)1123 ms:

#include<bits/stdc++.h>
using namespace std ;
typedef long long ll ;
typedef pair<int , int> pii ;
const int maxn = 1005 ;
const int maxm = 2e4 + 5 ;
set<int> row[maxm] , col[maxm] ;
int n ;
map<pair<pii , pii> , bool> vis ;
map<pii , int> id ;
ll b[maxn * maxn] ;
int cur = 0 ;
struct node
{
	int x , y ;
	bool operator< (const node &s) const
	{
		if(y != s.y)  return y < s.y ;
		else  return x < s.x ;
	}
} a[maxn] ;
void change(int &x , int &y)
{
	if(x * y > 0)  
	  x = abs(x) , y = abs(y) ;
	else
	  x = -abs(x) , y = abs(y) ;
	int d = __gcd(abs(x) , y) ;
	x /= d , y /= d ;
}
bool ok(int i , int j)
{
	int dx = a[j].x - a[i].x ;
	int dy = a[j].y - a[i].y ;
	change(dx , dy) ;
	int bx = dx , by = dx * a[i].y - dy * a[i].x ;
	change(bx , by) ;
	pii a = make_pair(dx , dy) , b = make_pair(bx , by) ;
	if(vis[make_pair(a , b)])  return 0 ;
	else  return 1 ;
}
void add(int i , int j)
{
	int dx = a[j].x - a[i].x ;
	int dy = a[j].y - a[i].y ;
	change(dx , dy) ;
	int bx = dx , by = dx * a[i].y - dy * a[i].x ;
	change(bx , by) ;
	pii a = make_pair(dx , dy) , c = make_pair(bx , by) ;
	vis[make_pair(a , c)] = 1 ;
	if(id[a] == 0)  id[a] = ++ cur ;
	b[id[a]] ++ ;
}
ll cal()
{
	ll xie = 0 ;
	for(int i = 1 ; i <= n ; i ++)
	  for(int j = i + 1 ; j <= n ; j ++)
	  {
	  	if(a[i].x == a[j].x || a[i].y == a[j].y)  continue ;
	  	else if(!ok(i , j))  continue ;
	  	else  add(i , j) , xie ++ ;
	  }
	return xie ;
}
ll solve()
{
	ll sum = 0 ;
	ll ans = 0 ;
	for(int i = 1 ; i <= cur ; i ++)  sum += b[i] ;
	for(int i = 1 ; i <= cur ; i ++)  ans += b[i] * (sum - b[i]) ;
	return ans / 2 ;
}
int main()
{
	scanf("%d" , &n) ;
	for(int i = 1 ; i <= n ; i ++)
	{
		scanf("%d%d" , &a[i].x , &a[i].y) ;
		a[i].x += 1e4 , a[i].y += 1e4 ;
	}
	sort(a + 1 , a + n + 1) ;
	ll xie = 0 , heng = 0 , shu = 0 ;
	for(int i = 1 ; i <= n ; i ++)
	{
		row[a[i].x].insert(a[i].y) ;
		col[a[i].y].insert(a[i].x) ;
	}
	for(int i = 0 ; i <= 2e4 ; i ++)
	{
		heng += (row[i].size() > 1) ;
		shu += (col[i].size() > 1) ;
	}
	xie = cal() ; 
	ll ans = 0 ;
	ans += heng * shu ;
	ans += heng * xie ;
	ans += shu * xie ;
	ans += solve() ;
	printf("%lld\n" , ans) ; 
	return 0 ;
}

代码2(最简分数存储斜线)873ms:

#include<bits/stdc++.h>
using namespace std ;
typedef long long ll ;
typedef pair<double , double> pdd ;
const int maxn = 1005 ;
const int maxm = 2e4 + 5 ;
set<int> row[maxm] , col[maxm] ;
int n ;
map<pdd , bool> vis ;
map<double , int> id ;
ll b[maxn * maxn] ;
int cur = 0 ;
struct node
{
	int x , y ;
	bool operator< (const node &s) const
	{
		if(y != s.y)  return y < s.y ;
		else  return x < s.x ;
	}
} a[maxn] ;
bool ok(int i , int j)
{
	double dy = double(a[i].y - a[j].y) ;
	double dx = double(a[i].x - a[j].x) ;
	double k = dy / dx , b = double(a[i].y) - k * a[i].x ;
	if(vis[make_pair(k , b)])  return 0 ;
	else  return 1 ;
}
void add(int i , int j)
{
	double dy = double(a[i].y - a[j].y) ;
	double dx = double(a[i].x - a[j].x) ;
	double k = dy / dx , c = double(a[i].y) - k * a[i].x ;
	vis[make_pair(k , c)] = 1 ;
	if(id[k] == 0)  id[k] = ++ cur ;
	b[id[k]] ++ ;
}
ll cal()
{
	ll xie = 0 ;
	for(int i = 1 ; i <= n ; i ++)
	  for(int j = i + 1 ; j <= n ; j ++)
	  {
	  	if(a[i].x == a[j].x || a[i].y == a[j].y)  continue ;
	  	else if(!ok(i , j))  continue ;
	  	else  add(i , j) , xie ++ ;
	  }
	return xie ;
}
ll solve()
{
	ll sum = 0 ;
	ll ans = 0 ;
	for(int i = 1 ; i <= cur ; i ++)  sum += b[i] ;
	for(int i = 1 ; i <= cur ; i ++)  ans += b[i] * (sum - b[i]) ;
	return ans / 2 ;
}
int main()
{
	scanf("%d" , &n) ;
	for(int i = 1 ; i <= n ; i ++)
	{
		scanf("%d%d" , &a[i].x , &a[i].y) ;
		a[i].x += 1e4 , a[i].y += 1e4 ;
	}
	sort(a + 1 , a + n + 1) ;
	ll xie = 0 , heng = 0 , shu = 0 ;
	for(int i = 1 ; i <= n ; i ++)
	{
		row[a[i].x].insert(a[i].y) ;
		col[a[i].y].insert(a[i].x) ;
	}
	for(int i = 0 ; i <= 2e4 ; i ++)
	{
		heng += (row[i].size() > 1) ;
		shu += (col[i].size() > 1) ;
	}
	xie = cal() ; 
	ll ans = 0 ;
	ans += heng * shu ;
	ans += heng * xie ;
	ans += shu * xie ;
	ans += solve() ;
	printf("%lld\n" , ans) ; 
	return 0 ;
}
发布了187 篇原创文章 · 获赞 12 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/Irving0323/article/details/104075916
今日推荐