Openjudge P7834分成互质组题解

题目描述

给定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:分成互质组icon-default.png?t=N7T8http://noi.openjudge.cn/ch0205/7834/最后希望大家能够喜欢我的文章,多多支持我,有问题的小伙伴可以私信交流,大家共同进步! 

  • 18
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值