# DFS# Prime Number# Combinations# Backtracking

d357 - NOIP2002 2.选数

🔗 前往 ZeroJudge 原題

題目描述

題目要求從給定的 n 個整數中選取 k 個整數,計算所有可能的組合和,並統計其中為質數的組合數量。

解題思路

本題採用深度優先搜尋 (DFS) 搭配回溯法來產生所有可能的 k 個整數組合。對於每個組合,計算其和,然後判斷該和是否為質數。使用一個 map 來儲存已經計算過的組合和及其是否為質數的結果,避免重複計算。isPrime 函數用於判斷一個數字是否為質數。used 陣列用於追蹤哪些數字已經被選入當前組合,以避免重複使用。

複雜度分析

  • 時間複雜度: O(C(n, k) * sqrt(max_sum)),其中 C(n, k) 是從 n 個元素中選取 k 個元素的組合數,max_sum 是所有組合和的最大值。sqrt(max_sum) 是 isPrime 函數的複雜度。
  • 空間複雜度: O(C(n, k)),主要用於儲存 map 中已經計算過的組合和。

程式碼

#include <iostream>
#include <cmath>
#include <map>
using namespace std;
long long a[25],n,m,ans;
map <long long,bool> mp;
bool used[25];
bool isPrime(long long x){
	if(x%2==0)return 0;
	for(long long y=3;y<=sqrt(x);y+=2)
		if(x%y==0)return 0;
	return 1;
}
void dfs(int it,long long v,int k){
	if(k==m){
		if(mp.find(v)!=mp.end()){
			ans+=mp[v];
		}
		else{
			if(isPrime(v)){
				mp[v]=1;
				++ans;
			}
			else{
				mp[v]=0;
			}
		}
		return;
	}
	for(int i=it;i<n;++i){
		if(used[i]==0){
			used[i]=1;
			dfs(i+1,v+a[i],k+1);
			used[i]=0;
		}
	}
	return;
}
int main(){
	cin.tie(0); ios::sync_with_stdio(false);
	cin >> n >> m;
	for(int i=0;i<n;++i){
		cin >> a[i];
	}
	dfs(0,0,0);
	cout << ans;
}

Discussion