题目描述
给定n个正整数,将它们分组,使得每组中任意两个数互质。至少要分成多少个组?
输入格式
第一行是一个正整数n。1 <= n <= 10。
第二行是n个不大于10000的正整数。
输出格式
一个正整数,即最少需要的组数。
样例输入 6 14 20 33 117 143 175
样例输出 3
判断互质,即最大公因数为1,需要用到求最大公因数的函数:
int gcd(int a,int b){
int r=a%b;
while(r!=0){
a=b;
b=r;
r=a%b;
}
return b;
}
我们现在来简单证明一下这个函数,先把问题转化一下:求a和b的最大公因数,其实就是用边长为r的正方形填满一个长为a宽为b的矩形中,如果刚好填满,r一定是a和b的公因数,当r最大时,r就为a和b的最大公因数,如图:
紧接着,先截最大的正方形,直到不能在截出同样的正方形为止,如图:
问题就转化为了在一个新的矩形中求最大边长为c的正方形。因为r=a%b,所以此时,a=b,b=r重复操作,在剩余的矩形中再截最大的长方形,如图:
所以只要重复操作若干次,就一定能得到最大公因数r。所以就得到了上述函数。
因为不确定有几个组,每个组里有多少个数,此题建议用动态数组解决,要用到以下函数:
vector<int> g
g.size()表示g数组目前的长度;g.push_back(a)表示向g数组中添加一个新的数a
解法一:枚举法
因为数据范围特别小可以考虑用枚举法通过本题,代码很短很简单,理清枚举思路即可:
#include<bits/stdc++.h>
using namespace std;
vector<int> g[30];
int a[15],f[15],n,cnt;
int gcd(int a,int b){
int r=a%b;
while(r!=0){
a=b;
b=r;
r=a%b;
}
return b;
}
int main(){
int i,j,k,flag;
cin>>n;
for(i=1;i<=n;i++){
cin>>a[i];//输入n个数
}
for(i=1;i<=n;i++){
flag=1;//假设不能够存入已经开辟过的数组
for(j=1;j<=cnt;j++){//遍历已经开辟的cnt个组
for(k=0;k<g[j].size();k++){//一定要注意vector的插入是从0号位置开始的
if(gcd(g[j][k],a[i])!=1)break;//两个数不互质跳出循环,表示不能把数字放入这组
}
//若k<g[j].size()就表示循环被中断了,k>=g[j].size()表示正常结束
if(k>=g[j].size()){//如果循环正常结束,表示a[i]与该组所有的数都互质
g[j].push_back(a[i]);
flag=0;//表示能够存入已经开辟的数组
break;
}
}
if(flag==1){//如果不能存入现有组就开辟一个新的组
cnt++;
g[cnt].push_back(a[i]);//插入数
}
}
cout<<cnt;
return 0;
}
解法二:搜索
使用搜索的时候要尤其注意分组,关注范围。这里为了给各位小伙伴们带来新的启发,我们使用普通数组完成本题
首先定义一个minans表示我们的最小值,接着用一个二维数组a[i][j]表示第i组第j个数字;然后剩下的就是愉快的搜索了,这里没有什么难点,代码如下:
#include<bits/stdc++.h>
using namespace std;
int a[50][50],c[50],minans=0x7f7f7f7f,h,s[50],n;
int gcd(int a,int b){
int r=a%b;
while(r!=0){
a=b;
b=r;
r=a%b;
}
return b;
}
void work(int t){
int i,j;
if(t==n+1){
minans=min(minans,h);
return ;
}
for(i=1;i<=h;i++){
for(j=1;j<=s[i];j++){
if(gcd(a[i][j],c[t])!=1)break;
}
if(j>s[i]){//表示与该组所有的数都互质,就可以进行搜索
s[i]++;
a[i][s[i]]=c[t];
work(t+1);
a[i][s[i]]=0;//关注回溯顺序,“早出晚归,迟到早退”
s[i]--;
}
}
h++;//额外搜索单另成组的情况
s[h]=1;
a[h][1]=c[t];
work(t+1);
s[h]=0;//关注回溯顺序,“早出晚归,迟到早退”
a[h][1]=0;
h--;
}
int main(){
int i,j,k;
cin>>n;
for(i=1;i<=n;i++){
cin>>c[i];
}
work(1);
cout<<minans;
return 0;
}
以上就是分成互质组的搜索解法。
看懂了的小伙伴快去试试吧!
OpenJudge - 7834:分成互质组http://noi.openjudge.cn/ch0205/7834/最后希望大家能够喜欢我的文章,多多支持我,有问题的小伙伴可以私信交流,大家共同进步!