题目
7834:分成互质组
总时间限制: 1000ms 内存限制: 65536kB
描述
给定n个正整数,将它们分组,使得每组中任意两个数互质。至少要分成多少个组?
输入
第一行是一个正整数n。1 <= n <= 10。
第二行是n个不大于10000的正整数。
输出
一个正整数,即最少需要的组数。
样例输入
6
14 20 33 117 143 175
样例输出
3
来源
2008年第十三届“华罗庚金杯”少年数学邀请赛 决赛第5题
理解
- 某数跟别的数都不互质,该数独立为一组。
- 某数跟别数互质,那共同是一组。
- (精髓)某两数互质,等到乘积跟另数互质,则该三数都互质。
- 宽搜是一个根节点遍历树。现在分组是分成多个数(树),不用宽搜。
- 每个没分组的数就是一个组,跟剩下没分组的数遍历,互质就变成同一组,用他们的乘积继续找下一个没分组的数。
代码
#include <bits/stdc++.h>
using namespace std;
int n,d[15],
ans,//几个组
k[15];//分到哪个组,也是宽搜标记
int gcd(int a,int b){
if(b==0)return a;
return gcd(b,a%b);
}
void view(){
cout<<“显示”<<endl;
for(int i=1;i<=n;i++)cout<<i<<“\t”;cout<<endl;
for(int i=1;i<=n;i++)cout<<d[i]<<“\t”;cout<<endl;
for(int i=1;i<=n;i++)cout<<k[i]<<“\t”;cout<<endl;
}
int main(){
//freopen(“data.cpp”,“r”,stdin);
cin>>n;
for(int i=1;i<=n;i++)cin>>d[i];
for(int i=1;i<=n;i++){
if(k[i])continue;//分过的就不管
k[i]=++ans;//分组
for(int j=i+1;j<=n;j++)//遍历剩余数
if(gcd(d[i],d[j])==1&&!k[j])//跟改组乘积是否为互质,而且没有分组过
d[i]*=d[j],k[j]=ans;//把该数乘到乘积中,并分到该组,
//view();
}
cout<<ans;
return 0;
}
互质数判断
根据百度查找——
根据互质数的定义,可总结出一些规律,利用这些规律能迅速判断一组数是否互质。
(1)两个不相同的质数一定是互质数。如:7和11、17和31是互质数。
(2)两个连续的自然数一定是互质数。如:4和5、13和14是互质数。
(3)相邻的两个奇数一定是互质数。如:5和7、75和77是互质数。
(4)1和其他所有的自然数一定是互质数。如:1和4、1和13是互质数。
(5)两个数中的较大一个是质数,这两个数一定是互质数。如:3和19、16和97是互质数。
(6)两个数中的较小一个是质数,而较大数是合数且不是较小数的倍数,这两个数一定是互质数。如:2和15、7和54是互质数。
(7)较大数比较小数的2倍多1或少1,这两个数一定是互质数。如:13和27、13和25是互质数。
当然互质判断本质上是公约数有且仅有1。
小结
还是要从分析数据开始。
把两质数的乘积作为新对象找别的互质数,这个是个大胆的举措。