题目描述:
给定 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;
}