(第11回ブルーブリッジカップ州大会)質問I:平面セグメンテーション(検索ルール)

トピックリンク:「ブルーブリッジカップ」練習システム

分析:この質問では、最初にいくつかの直線を引いてルールを見つけることができます

これらの3本の線は7つの領域を形成します。線を追加して、何が起こるかを確認してみましょう(新しい線は赤で表示されます

もともと直線は3本しかないので、新しく追加した直線と元の直線の交点数は3つの場合(すべての直線が平行な場合を考慮する必要はありません)、 1つの交差点、2つの交差点、3つの交差点、これら3つのケースを別々に分析してみましょう。

 最初のケース:新しい線は元の線と交差しています

 

上下の線が平行であることに注意してください。この時点で9つの領域があり、元のベースで2つの領域が追加され、新しく追加された線とすべての元の線の交点の数は1です。

2番目のケース:新しい線には元の線との交差が2つあります

 

 このとき、10のエリアがあり、元のラインに基づいて3つのエリアが追加され、新しく追加された線とすべての元の線との交点の数は2です。

最後に、新しく追加された線が元の線と3つの交差を形成する状況を見てください。

 このとき、11のエリアがあり、元のラインに基づいて4つのエリアが追加され、新しく追加された線とすべての元の線の交点の数は3です。

これらの状況を分析した結果、元のグラフに基づいて、新しい直線と元の直線がn個の交点を形成する場合、直線を追加することによって形成されるグラフの部分の数というルールが見つかったようです。線は元の線より大きくなります。グラフの部分の数はn+1多くなります。

これはどのような状況でも当てはまります。これにより、この問題に簡単に対処できます。最初にすべての線を重複排除し、次に最初に線を追加します。このとき、平面は2つの部分に分割され、次に直線を1つずつ追加し、元の直線との交点の数を求めて、新しく追加されたパーツの数を求めます。すべての直線を処理した後、答えを得ることができます。

交点を見つける過程で、連立方程式を解く必要があります。式の導出過程を以下に示します。

 最後にコードを与えます:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#include<cmath>
#include<queue>
#include<set> 
using namespace std;
const int N=1e3+10;
typedef pair<double,double>PII;
set<PII>s;//存放直线 
set<PII>points;//存放交点 
double k[N],b[N];
int main()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		double kk,bb;
		scanf("%lf%lf",&kk,&bb);
		s.insert({kk,bb});
	}
	int tt=0;
	set<PII>::iterator it;//set迭代器 
	for(it=s.begin();it!=s.end();it++)
	{
		k[++tt]=(*it).first;
		b[tt]=(*it).second;
	}
	long long ans=2;//从第二条直线开始遍历,第一条直线将平面划分为2部分 
	for(int i=2;i<=tt;i++)
	{
		points.clear();
		for(int j=1;j<=i;j++)
		{
			if(k[i]==k[j]) continue;//两直线平行则不可能有交点 
			double x=k[i]*(b[j]-b[i])/(k[i]-k[j]);
			double y=(k[i]*b[j]-k[j]*b[i])/(k[i]-k[j]);
			points.insert({x,y});
		}
		ans+=points.size()+1;//当前直线与其他直线有m个交点那么就会多产生m+1块区域
	}
	printf("%lld",ans);
	return 0;
}

おすすめ

転載: blog.csdn.net/AC__dream/article/details/123985493