Description
给定 n 个正整数,将它们分组,使得每组中任意两个数互质。
至少要分成多少个组?
Input
第一行是一个正整数 n ( 1 ≤ n ≤ 10 )。
第二行是 n 个不大于 10000 的正整数。
Output
一个正整数,即最少需要的组数
Sample Input
6
14 20 33 117 143 175Sample Output
3
思路:利用dfs搜索所有符合题意(各组内两两互质)的情况,并更新组数最小值
代码(含注释):
#include<bits/stdc++.h>
using namespace std;
#define N 12
int arr[N];//存储所有数值
int se[N][N];//分组
int num[N];//记录各组存储数值的数量
int k = 0;//当前一共有k组
int n, ans = 100;
int gcd(int a, int b) {
return b ? gcd(b, a % b) : a;
}
//分配第x个数值
void dfs(int x) {
//当分配第n+1个数值时说明前n个数值全部分组完毕
if (x == n + 1) {
ans = min(ans, k);
return;
}
//将当前第x个数值分配到当前各组中或者自身独立另开一组
for (int i = 1; i <= k + 1; i++) {
int j = 0;
//判断第i组内各数值与arr[x]是否互质
for (j = 0; j < num[i]; j++) {
if (gcd(arr[x], se[i][j]) != 1)
break;
}
//j==num[i]说明第i组中所有的数均与arr[x]互质
if (j == num[i]) {
if (j == 0) {//j==0说明arr[x]自身另开一组
if (ans <= k + 1)//剪枝:如果新开一组大于当前最小值,则没有新开一组的必要
continue;
else k++;
}
se[i][num[i]++] = arr[x];
dfs(x + 1);
if (j == 0)k--; //回溯
num[i]--; //回溯
}
}
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &arr[i]);
//先将第一个数值分配到第一组中
se[1][num[1]++] = arr[1];
k = 1;
//继而分配第二个数值
dfs(2);
printf("%d\n", ans);
return 0;
}
代码(不含注释):
#include<bits/stdc++.h>
using namespace std;
#define N 12
int arr[N];
int se[N][N];
int num[N];
int k = 0;
int n, ans = 100;
int gcd(int a, int b) {
return b ? gcd(b, a % b) : a;
}
void dfs(int x) {
if (x == n + 1) {
ans = min(ans, k);
return;
}
for (int i = 1; i <= k + 1; i++) {
int j = 0;
for (j = 0; j < num[i]; j++) {
if (gcd(arr[x], se[i][j]) != 1)
break;
}
if (j == num[i]) {
if (j == 0) {
if (ans <= k + 1)
continue;
else k++;
}
se[i][num[i]++] = arr[x];
dfs(x + 1);
if (j == 0)k--;
num[i]--;
}
}
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &arr[i]);
se[1][num[1]++] = arr[1];
k = 1;
dfs(2);
printf("%d\n", ans);
return 0;
}