【NOIP1998】 三連擊 題解
阿新 • • 發佈:2021-10-15
文章轉載前需和原作者聯絡,否則追究法律責任
題目連結:https://www.luogu.com.cn/problem/P1008
首先我們來分析一下題目。要求是列舉三個數,比例為1:2:3,且各個數字由1-9組成。
我們採用列舉的方式來進行這道題目。首先,數字滿足兩個條件(比例為1:2:3,且各個數字由1-9組成),我們只需要列舉其中的一種條件,然後判斷第二種條件是否滿足即可。
舉例:列舉數字比例1:2:3,然後進行判斷數位是否由1-9組成。程式碼框架:
#include<bits/stdc++.h> using namespace std; int main(){ int a,b,c; for(int a=123;a<=333;a++){ b=2*a;c=3*a; ... cout<<a<<' '<<b<<' '<<c<<endl; } }
最重要的是來判斷各個數位是否由1-9組成。此時,我們可以使用一個函式,叫做sprintf
。
我們知道,printf函式可以向標準輸出輸出內容,例如:
假設a=2
printf("a=%d",a);
此時標準輸出會顯示:a=2
sprintf的用法和printf類似,因此,我們如果這樣寫:
sprintf(s,"a=%d",a);
如果s是一個C風格字串,那麼s字串將會變為:“a=2”。
是否發現了什麼?如果我們這樣寫:
sprintf(s,"%d%d%d",a,b,c);
那麼,如果a=123,b=456,c=789,那麼s將會變為:“123456789”。事實上,sprintf經常用於把數字轉為字串。
這樣,我們把三個數連在了一起,這樣就可以從s[0]列舉到s[9],列舉各個數字出現的個數即可。
完整程式碼如下:
#include<bits/stdc++.h> using namespace std; int main(){ int a,b,c; for(int a=123;a<=333;a++){ b=2*a;c=3*a; char s[10]; sprintf(s,"%d%d%d",a,b,c); int flag[10]; memset(flag,0,sizeof(flag)); for(int i=0;i<9;i++) flag[s[i]-'0']++;//統計數字的個數 for(int i=1;i<=9;i++){ if(flag[i]!=1)goto next;//出現次數不為1則跳過 } cout<<a<<' '<<b<<' '<<c<<endl; next: continue; } }
至於另一種解法,也就是隻列舉1-9的全排列,然後分段輸出三位數,這裡也簡單闡述一下。
列舉全排列可以使用遞迴搜尋的方法,框架大家都應該很清楚,我也不寫了。當然,也可以使用STL演算法庫的next_permutation函式,進行全排列的計算。
我們把全排列計算出後,就把9位分為三段,判斷比例是否為1:2:3。
程式碼如下:(使用next_permutation計算全排列)
注:總列舉次數為9的階乘,也就是362880
#include<bits/stdc++.h>
using namespace std;
int s[9]={1,2,3,4,5,6,7,8,9};
int main(){
for(int i=0;i<362880;i++){
int a=s[0]*100+s[1]*10+s[2];
int b=s[3]*100+s[4]*10+s[5];
int c=s[6]*100+s[7]*10+s[8];
if((b==2*a) && (c==3*a)){
printf("%d %d %d\n",a,b,c);
}
next_permutation(s,s+9);
}
return 0;
}