您的位置:首页 > 运维架构

POJ(7834)-----分成互质组(openjudge)

2017-07-09 10:49 453 查看

分成互质组

Description

给定n个正整数,将它们分组,使得每组中任意两个数互质。至少要分成多少个组?

Input

第一行是一个正整数n。1 <= n <= 10。

第二行是n个不大于10000的正整数。

Output

一个正整数,即最少需要的组数。

Sample Input

6

14 20 33 117 143 175

Sample Output

3

Source

2008年第十三届“华罗庚金杯”少年数学邀请赛 决赛第5题

做题地址:OpenJudge-7084:分成互质组 (需要注册)

求解此题,有各种各样的歪门邪道,最常用的有两种:

1:暴力 for for for

2: 套数学方法

作者选择暴力(︿( ̄︶ ̄)︿噜噜噜噜)

而在暴力for下面还有很多细小的优化处理

可以使用求最大连通块的种子法优化:

第一个for寻找未被种子标记的数,使用另一个种子初始化(推荐从1递增)

第二个for寻找与相同种子互质的数,如果全部互质,就加入

最后查看种子的值,得出组数(从1递增的原因之一)

而使用数学方法,则是用了一个性质:

如果a与b互质,c与b互质,则有a*c与b互质

这样如果有两个数互质,就把它们乘起来,继续判断,如果不互质就另开一个。这样确实能避免暴力搜索中的第二个for,但是:

第一行是一个正整数n。1 <= n <= 10。

第二行是n个不大于10000的正整数。

假设遇上最坏的情况,那么乘积的近似值应为10000^10,也就是;

题目极限数据近似值:10000^10=100,000,000,000,000,000,000,000,000,000,000,000,000,00(不要数了,40个0)

long long int
极值:2^63-1=922,337,203,685,477,580,7(19位数)

unsigned long long
(无符号超长整型)极值:2^64-1=184,467,440,737,095,516,15(19位数)

作者在网上查了一下,最接近10000的10个质数是:

8821 8831 8837 8839 8849 8861 8863 8867 8887 8893

所以,题目极限数据为:

8821*8831*8837*8839*8849*8861*8863*8867*8887*8893

=296,328,592,112,670,000,000,000,000,000,000,000,000,0(40位数)

仍然大于C++中标准数据类型的极值

所以还是暴力好用(︿( ̄︶ ̄)︿噜噜噜噜)

暴力搜索代码

#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
struct data{
int s,count;
bool use;
}a[15];
int n,k;
int gcd(int x,int y)
{
int z = y;
while(x%y!=0)
{
z=x%y;
x=y;
y=z;
}
return z;
}
void dfs(int m)
{
for(int i=1;i<=n;i++)
{
bool flag=1;
if(!a[i].use)
{
for(int j=1;j<=n;j++)
if(a[j].count==m)
if(gcd(a[j].s,a[i].s)!=1)
{
flag=0;
break;
}
if(flag)
{
a[i].use=1;
a[i].count=m;
}
}
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i].s);
for(int i=1;i<=n;i++)
{
if(!a[i].use)
{
a[i].use=1;
a[i].count=++k;
dfs(k);
}
}
printf("%d\n",k);
return 0;
}


IN THE END

前面说使用数学方法遇上稍刁钻的数据就会溢出,但是当我交上去后,莫名其妙的

Accepted了!

Accepted了!

Accepted了!

真是不知其尬无以尬人也((⊙o⊙)…)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  poj