1. 程式人生 > 其它 >acwing 1118. 分成互質組(dfs搜尋+剪枝)

acwing 1118. 分成互質組(dfs搜尋+剪枝)

目錄

題目傳送門

題目描述

給定 nn 個正整數,將它們分組,使得每組中任意兩個數互質。

至少要分成多少個組?

輸入格式

第一行是一個正整數 nn。

第二行是 nn 個不大於10000的正整數。

輸出格式

一個正整數,即最少需要的組數。

資料範圍

1≤n≤10

輸入樣例:

6
14 20 33 117 143 175

輸出樣例:

3

dfs剪枝搜尋

分析

小貓爬山問題很像

對於每個數

  • 如果他和某一組內所有數互質,就可以將它加到這個組;然後回溯
  • 新開一個組,把這個數加到新的組

對於如何判斷互質:用定義

兩個數互質:就是兩個數的最大公約數是1

程式碼

#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
int gcd(int a, int b)
{
    return b ? gcd(b, a % b) : a;
}
bool isZ(int a, int b)
{
    if(gcd(a, b) > 1) return false;
    else              return true;
}
int ans = 0x3f3f3f3f;
vector<int> h[12];
int a[12];
int n;

void dfs(int u, int k)
{
    if(k >= ans) return; // 剪枝

    if(u >= n)
    {
        ans = min(ans, k);
        return;
    }

    for(int i = 0; i < k; i++)
    {
        vector<int> tmp = h[i]; // 第k組有的所有互質的數
        bool flag = true;
        for(int j = 0; j < tmp.size(); j++)
        {
            if(!isZ(a[u], tmp[j]))
            {
                flag = false;
                break;
            }
        }

        if(flag)
        {
            h[i].push_back(a[u]);
            dfs(u+1, k);
            h[i].pop_back(); // 恢復現場
        }
    }

    h[k].push_back(a[u]);
    dfs(u+1, k+1);
    h[k].pop_back();
}

int main()
{
    cin >> n;
    for(int i = 0; i < n; i++) cin >> a[i];

    dfs(0, 0);

    cout << ans;
    return 0;
}

時間複雜度

參考文章

https://www.acwing.com/solution/content/10364/