AcWing 1118 分成互质组【DFS 搜索顺序 ☆】

题目描述:

给定 n 个正整数,将它们分组,使得每组中任意两个数互质。

至少要分成多少个组?

输入格式

第一行是一个正整数 n。

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

输出格式

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

数据范围

1≤n≤10

输入样例:

6
14 20 33 117 143 175

输出样例:

3

分析:

1、确定每一个组中能放哪些数字。
a.某个数放到最后一组中
b.新开一组

这种枚举方式中,如果某个数能够放到当前最后一组中,一定比新开一组 的 方案数少。 枚举的每一个组,都是到了不能再放下任何数的时候(即多加一个数就会导致不是互质的存在),才去新开一个组。这种和第二种枚举方式不同,已经确定的组就不会再放任何的数,而第二种枚举方式,每个组都有可能再加数进去,所以不行。

#include <iostream>
#include <vector>

using namespace std;

const int N = 15;

int p[N];
int n;
vector<int> group[N];
int res = 15;
int st[N];

int gcd(int a , int b){
	return b ? gcd(b, a %b) : a; 
}

bool check(int g , int i ){
	for(int j = 0 ; j < group[g].size() ; j ++)
	{
		if( gcd(group[g][j] , p[i]) != 1)
			return false;
	}
	return true;
}

void dfs(int g , int start , int cnt){ //当前是第g组  , 当前已分配的数字的总数 
	if( g >= res ) return ; //当枚举的组数已经超过了res,那就没必要继续做下去了
	if( cnt == n ) res = g + 1; //由于if语句的存在,如果还能得到cnt == n 的结果那么g一定比当前的res小
	
	bool flag = true;//判断一下 如果能够放到最后一组就不会新开一组
	for(int i = start ; i < n ; i ++) //start组合型枚举方式
	{
		if( !st[i] && check(g,i) )
		{
			st[i] = true;
			group[g].push_back( p[i] );
			dfs( g , i+1 , cnt+1);
			group[g].pop_back();
			st[i] = false;
			flag = false;
		}
	}
	
	if( flag ) dfs(g+1 , 0 , cnt );//不能放到最后一组中,新开一组
}
 
int main(){
	cin >> n;
	for(int i = 0 ; i < n ; i ++ ) cin >> p[i];
	
	dfs(0 , 0 , 0);
	cout << res << endl;
	return 0;
}

2、确定每一个数能放到哪个组中。
注意点:并不是说某个数,能够放到已经有的组中就一定比新开一组的总方案数少!!!(不一定哦)

#include <iostream>
#include <vector>

using namespace std;

const int N = 15;

int number[N];
int n;
vector<int> group[N];
int res = 15;

int gcd(int a ,int b){
	return b? gcd(b,a%b) : a; 
}

void dfs(int u,int gp){
	if( u == n )
	{
		res = min(res , gp);
		return ;
	}
	
	for(int i = 0 ; i < gp ; i ++)
	{
		bool flag = true;
		for(int j = 0 ; j < group[i].size() ; j ++)
		{
			if( gcd(number[u] , group[i][j] ) != 1)
			{
				flag = false;
				break;
			}
		}
		if( flag == true )
		{
			group[i].push_back(number[u]);
			dfs(u+1,gp);
			group[i].pop_back();
		}
 	}
 	
 	group[gp].push_back(number[u]);
 	dfs(u+1,gp+1);
 	group[gp].pop_back();
 	
}

int main(){
	cin >> n;
	for(int i = 0 ; i < n ; i ++) cin >> number[i];
	
	dfs(0,0);
	
	cout << res << endl;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值