圆的分割方案
圆的分割方案
圆是一个极度完美的几何体。它的完美体现在各个方向的绝对对称上。但是,这很容易造成我们难以使用线性的观点来描述圆。下面将通过例题,具体讲解如何用线性的观点解决圆的分割问题。
问题:
一天,瑞兹在寻找远古符文的旅程中发现了一个祭坛,敏锐的瑞兹发现这个祭坛不简单,很有可能藏有符文。在祭坛旁的石碑上记载着关于祭坛的一些情况:祭坛是一个圆形,在祭坛的边缘,放置着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;
}