Vijos1128.選數

試題請參見: https://vijos.org/p/1128

題目概述

已知 n 個整數 x1,x2,…,xn, 以及一個整數 k(k<n). 從 n 個整數中任選 k 個整數相加, 可分別得到一系列的和. 例如當 n=4, k=3, 4 個整數分別爲 3, 7, 12, 19 時, 可得全部的組合與它們的和爲:

3+7+12=22  3+7+19=29  7+12+19=38  3+12+19=34.

現在, 要求你計算出和爲素數共有多少個.
例如上例, 只有一種的和爲素數:3+7+19=29.

解題思路

很明顯需要用回溯的思路解決, 在n個數中選取k個數.
得到k個數後求和, 並判斷是否爲素數.

遇到的問題

解題過程中主要遇到兩個問題:

  1. 原題中敘述求素數共有多少種, 於是我使用set去重. 然後妥妥的WA了.
  2. 在遞歸時, 需要指定當前搜索開始的下標(代碼中的searchIndex), 否則結果會重複.

源代碼

#include <iostream>
#include <cmath>

const int MAX_N = 20;

int getSum(long long*, int, int);
void getSum(long long*, bool*, int, int, int, int, long long, int&);
bool isPrime(long long);
bool isAppeared(long long);

int main() {
    int n = 0, k = 0;
    long long numbers[MAX_N] = {0};

    std::cin >> n >> k;
    for ( int i = 0; i < n; ++ i ) {
        std::cin >> numbers[i];
    }
    std::cout << getSum(numbers, n, k) << std::endl;

    return 0;
}

/**
 * 獲取不同的素數結果的個數.
 * @param  numbers n個數序列的集合
 * @param  n       序列的長度
 * @param  k       選取數的個數
 * @return 不同的素數結果的個數
 */
int getSum(long long* numbers, int n, int k) {
    int totalResults = 0;
    bool isUsed[MAX_N] = {0};

    getSum(numbers, isUsed, n, k, 0, 0, 0, totalResults);

    return totalResults;
}

/**
 * 回溯: 獲取n個數中選擇k個值的總和.
 * @param  numbers         n個數序列的集合
 * @param  isUsed          n個數的選擇情況(第i個數是否被選中)
 * @param  n               序列的長度
 * @param  k               選取數的個數
 * @param  searchIndex     下次搜索的下標
 * @param  selectedNumbers 當前選擇的個數
 * @param  sum             當前的總和
 * @param  totalResults    當前不重複的和的個數
 */
void getSum(long long* numbers, bool* isUsed, int n, int k, int searchIndex, int selectedNumbers, long long sum, int& totalResults) {
    if ( selectedNumbers == k ) {
        if ( isPrime(sum) ) {
            ++ totalResults;
        }
    }

    for ( int i = searchIndex; i < n; ++ i ) {
        if ( !isUsed[i] ) {
            isUsed[i] = true;
            getSum(numbers, isUsed, n, k, i, selectedNumbers + 1, sum + numbers[i], totalResults);
            isUsed[i] = false;
        }
    }
}

/**
 * 判斷一個數是否爲素數.
 * @param  x 待判斷的值
 * @return 該數值是否爲素數
 */
bool isPrime(long long x) {
    if ( x <= 2 ) {
        return false;
    }
    for ( int i = 2; i <= std::sqrt(x); ++ i ) {
        if ( x % i == 0 ) {
            return false;
        }
    }
    return true;
}
發佈了50 篇原創文章 · 獲贊 1 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章