先上題目:
一般而言,對於求質數,素數,有三種方法(~~抱歉,是我只知道三種~~)
①首先!最簡單的是,對一個數從2到其平方跟,檢測是否能夠整除,均不能被整除,素數出現!
bool prime(int x)
{
for (int j=2;j<=sqrt(x);j++)
if (x%j==0) return false;
return true;
}
②其次,就是埃氏篩法了,通過將已有的質數進行倍數放大,得到的數必然不是素數,然後逐個質數進行放大,最終取其補集即可!額,對了,0,1除外,這輛不是素數也不是合數。
void Prime()
{
for (int i=0; i<MAXN; i++) prime[i]=1; //先把每個數都定義爲合數
prime[0]=prime[1]=0;
for (int i=2; i<MAXN; i++)
{
if (!prime[i]) continue;
for (int j=i*2; j<MAXN; j+=i) prime[j] = 0; //將i的倍數標記爲合數
}
}
③最後,那就本次的重點了!線性篩法,亦稱歐拉篩法
void Pn() {//先把質數表做出來
pn[0] = 2;
for (int i = 3; i < 20000; i++) {
bool flag=true;
for (int j = 0; j < x; j++) {
if (i % pn[j] == 0) {
flag = false;
break;//能被一個最小的素數整除,非素數
}
}
if (flag) {
pn[x++] = i;
}
}
}
分析:pn用來存取,所有已經獲取的質數,x則爲已獲取的所有質數的個數,從3開始,遍歷質數表,3不能整除任何素數,則3也是一個素數。(此處補充一個數學原理:所有的合數均存在一個最小質數因子,就像6,它的因子有1,6,2,3,而2就是它的最小質數因子)
每次整除一個最小的質數將會跳出循環,所以每個數字,只會被最小的質數篩一次(非常重要!!核心思想!!),所以整個
算法的時間複雜度接近於o(N).
THEN!
回過來,看看題目,我只要加個搜索就好了,找到我就停。
#include <iostream>
#include <cmath>
#include <iomanip>
using namespace std;
//p1579,分析:先做出質數表,然後通過dfs來找出匹配三個質數。
int pn[20000];//用於記錄已有的素數
int x=1;//記錄素數的個數
int sum;//記錄和
int ans[3] = {0};//記錄三個加數所屬的質數位置
//int used[20000] = { 0 };//記錄該質數是否被使用過
void Pn() {//先把質數表做出來
pn[0] = 2;
for (int i = 3; i < 20000; i++) {
bool flag=true;
for (int j = 0; j < x; j++) {
if (i % pn[j] == 0) {
flag = false;
break;//能被一個最小的素數整除,非素數
}
}
if (flag) {
pn[x++] = i;
}
}
}
bool flag = false;
void dfs(int count) {
if (flag) {//已經找到則無需再找
return;
}
if (count == 3) {//到了個數就判斷是否滿足
if (pn[ans[0]]+pn[ans[1]]+pn[ans[2]] == sum) {
flag = true;
cout << pn[ans[0]] << " " << pn[ans[1]] << " " << pn[ans[2]];
}
return;
}
for (int i = 0; i < x; i++) {
/*if (used[i] == 0) {
used[i] = 1;
ans[count] = i;
dfs(count + 1);
used[i] = 0;
}*/
ans[count] = i;
dfs(count + 1);
}
}
int main() {
Pn();
/*for (int i = 0; i < x; i++)
{
cout << pn[i] << " ";
}*/
cin >> sum;
dfs(0);
}
原本以爲用dfs,後來發現元素可以重用,簡單搜索即可。