圆的分割方案

圆的分割方案

圆是一个极度完美的几何体。它的完美体现在各个方向的绝对对称上。但是,这很容易造成我们难以使用线性的观点来描述圆。下面将通过例题,具体讲解如何用线性的观点解决圆的分割问题。

问题:

一天,瑞兹在寻找远古符文的旅程中发现了一个祭坛,敏锐的瑞兹发现这个祭坛不简单,很有可能藏有符文。在祭坛旁的石碑上记载着关于祭坛的一些情况:祭坛是一个圆形,在祭坛的边缘,放置着n个魔法阵。 魔法师每次可以取其中的四个魔法阵,若这四个魔法阵构成了一个矩形,就有一定的可能启动祭坛。现在你能告诉瑞兹,这些魔法阵能构成多少不重复的矩形。两个矩形不重复,当且仅当选取的4个魔法阵的位置不同。

输入

第1行一个数字n(n<=500)代表魔法阵的数量。

接下来的n行,每行1个数字s(1<=s<=15),代表这n个魔法阵所分隔的各个圆弧的长度。

给出的圆弧长度按顺时针方向给出。

输出:

一个整数,代表可以形成的不同矩形的个数。

样例输入

8 1 2 2 3 1 1 3 3

样例输出

3


问题的解决方法自然是暴力破解,寻找所有可能

官方的解析如下:

矩形的两条对角线,一定是圆的两条直径。我们可以枚举矩形的第一个点,那么矩形的第三个点一定与第一个点相距圆的周长/2的距离,确定一条直径后,我们可以在第一个点与第三个点之间枚举第二个点,以确定另一条对角线。 这样每条直径会被计算两次,答案须除以2特殊的,若圆的周长为奇数则 无解

无论是确定一个点,或是确定与之相对应的点,都需要有始有终。这就需要正确的描述点在圆上的位置。这个位置必须是唯一可确定可查找的。为达到这个目的,我们需要在圆上选定一个参考点,以此描述其他点的位置。很简单的,我们这里采用第一个所给圆弧前(逆时针)的那个点作为参考点。每个点对参考点的(逆时针)距离作为描述该点的唯一方式。能够构成直径的两个点,不仅是距离之间相差圆周长的一半,而且还有可能参与构成一个矩形的对角线。利用这个性质,我们写出如下的代码:

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

int n;
vector<int> psd;
int sum;

int readin()
{
	cin>>n;
	sum=0;
	int c;
	psd.push_back(0);
    //这里是第一个点(参考点)到参考点的距离
	for(int i=0;i<n;i++)
	{
		cin>>c;
		sum+=c;
		psd.push_back(sum);
	}
	return 0;
}

int main()
{
	readin();
	if(sum&1)
	{//如果周长是奇数就没有了 
		cout<<0<<endl;
		return 0;
	}
	int num=0;
	for(int i=0;psd[i]<sum/2;i++)
	{//遍历参考点距离内一半的圆周,因为矩形的四个点一定是对半分布在圆两侧的
		int s=psd[i]+sum/2;
		if(find(psd.begin(),psd.end(),s)==psd.end())continue;
		//没有找到第一条直径
		for(int k=i+1;psd[k]<s;k++)
		{//注意这里需要对sum取模
			if(find(psd.begin(),psd.end(),(psd[k]+sum/2)%sum)!=psd.end())
				num++;
		}
	}
	num/=2;
    //对于每个矩形,直径每一侧都有两个矩形的点,
    //都会作为内层与外层循环各被查找到一次,
    //所以要除以二。
	cout<<num<<endl;
	return 0;
}

posted @ 2020-05-13 13:44  SavenNeer  阅读(1085)  评论(0编辑  收藏  举报