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

分成互质组

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
#include
#include
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⊙)…)

你可能感兴趣的:(C++入门,搜索专项,POJ题目,openjudge题目)