在算法競賽中,不少問題是來不及用數學公式推導出來的。或者說根本就找不到數學規律,這時咱們就須要使用枚舉來暴力破解。ios
不過枚舉也是須要腦子的,一味的暴力只能超時。所以我這裏選擇了幾道mooc上經典的題目來作複習。c++
思路:算法
從2到N枚舉a的值,2到a枚舉d的值,2到d的枚舉b的值,2到c枚舉b的值。當數組
知足a*a*a==b*b*b+c*c*c+d*d*d
的時候對結果輸出。
代碼以下:
#include <iostream> using namespace std; int main() { int N; cin>>N; for(int a=2;a<=N;a++){ for(int d=2;d<=a;d++){ for(int c=2;c<=d;c++){ for(int b=2;b<=c;b++){ if(a*a*a==b*b*b+c*c*c+d*d*d) cout<<"Cube = "<<a<<", Thiple = ("<<b<<","<<c<<","<<d<<")"<<endl; } } } } return 0; }
運行結果以下:spa
作此題咱們首先會有個思路就是從d+1開始一個一個嘗試,直至知足條件(
(k-p)%23==0&&(k-e)%28==0&&(k-i)%33==0)
因此咱們很輕易地就能寫出對應的代碼。代碼以下:
#include <iostream> using namespace std; int main(){ int p,e,i,d,N=0; while(cin >> p >> e >> i >> d&&p!=-1) { int k; for(k=d+1;(k-p)%23||(k-e)%28||(k-i)%33;k++); cout<<"Case "<<++N<<": The next triple peak occurs in "<<k-d<<" days."<<endl; } return 0; }
不過在此咱們是否會有個疑問。一個一個的嘗試是否過於浪費時間了?
這裏咱們給出另外一種思路。
咱們先枚舉出k+1後,第一個知足高峯的時間點做爲第一種高峯的基數,這時咱們須要等到k-p%23==0的時候中止。
這時的k表明着知足了k-p。
而後咱們枚舉下一種高峯的時間基數。此次咱們每次只須要+23就夠了。由於23之內確定不知足第一種高峯。
隨後咱們再枚舉第三個知足高峯的時間點的基數,這個基數-d就是咱們最終的答案,此次咱們每次跳過23*28個單位便可。
整體代碼以下所示。
#include <iostream> using namespace std; int main(){ int p,e,i,d,N=0; while(cin >> p >> e >> i >> d&&p!=-1) { int k; for(k=d+1;(k-p)%23;k++);//c++中正數就是true for(;(k-e)%28;k+=23); for(;(k-i)%33;k+=23*28); cout<<"Case "<<++N<<": The next triple peak occurs in "<<k-d<<" days."<<endl; } return 0; }
運行結果以下。
題目連接3d
1.每一個盤子稱的牌子不必定有4個。code
2.若是某個假幣可能輕可能重,不要continue,要以heavy----light的倆次形式輸出。blog
思路:ip
定義一個大小爲9字符串數組。做爲每次輸入的字符串。ci
依次假設每一個硬幣爲假的。而後從重到輕挨個枚舉,當找到假幣的時候輸出。
下面是AC代碼:
#include <iostream> #include <string> #include <map> using namespace std; int main(){ int N; cin>>N; map<char,int> m; for(int i=65;i<77;i++) { m[(char)i]=0; } while(N--){ string str[9]; cin>>str[0]>>str[1]>>str[2]>>str[3]>>str[4]>>str[5]>>str[6]>>str[7]>>str[8]; for(int i=65;i<77;i++){ int sign = 0; int left = 0,right = 0; string res=""; m[(char)i]=1; for(int k=0;k<3;k++) { for (int j = 0; j < str[0+3*k].length(); j++)left += m[str[0+3*k][j]]; for (int j = 0; j < str[1+3*k].length(); j++)right += m[str[1+3*k][j]]; if (left == right) res = "even"; if (left > right) res = "up"; if (left < right) res = "down"; if (res == str[2+3*k])sign++; left=0; right=0; } if(sign==3)cout<<(char)i<<" is the counterfeit coin and it is heavy.\n"; sign=0; res=""; m[(char)i]=-1; for(int k=0;k<3;k++) { for (int j = 0; j < str[0+3*k].length(); j++)left += m[str[0+3*k][j]]; for (int j = 0; j < str[1+3*k].length(); j++)right += m[str[1+3*k][j]]; if (left == right) res = "even"; if (left > right) res = "up"; if (left < right) res = "down"; if (res == str[2+3*k])sign++; left=0; right=0; } if(sign==3) cout<<(char)i<<" is the counterfeit coin and it is light.\n"; m[(char)i]=0; } } return 0; }
這道題着實有點難。不過咱們此次用枚舉的方法解答這個問題。
分析:
輸入一個5*6的矩陣,讓咱們從中選取一個按鈕方案,使最終全部燈都熄滅。
思路:
0、目標使全部燈的狀態變爲0。
一、想不干擾第1行別的燈的狀態來改變第1行,就須要按下面的按鈕才能準確的改變。
二、別的行數也是以此類推。
三、這樣別的行數的狀態都會隨着第一行的變化而肯定。
AC代碼以下:
#include <iostream> using namespace std; int Matrix[5][6]; int res[5][6]; int temp[5][6]; void Flip(int &a){ if(a) a=0; else a=1; } bool Check(){ for(int i=0;i<6;i++){ if(temp[4][i]) return false; } return true; } void print(int t){ cout<<"PUZZLE #"<<t<<endl; for(int i=0;i<5;i++){ for(int j=0;j<6;j++) { if(j==5)cout<<res[i][j]; else cout << res[i][j] << " "; } cout<<endl; } } int main(){ int N;cin>>N; for(int t=1;t<=N;t++){ for(int i=0;i<5;i++)for(int j=0;j<6;j++)cin>>Matrix[i][j];//輸入矩陣 for(int a=0;a<2;a++)for(int b=0;b<2;b++)for(int c=0;c<2;c++)for(int d=0;d<2;d++)for(int e=0;e<2;e++)for(int f=0;f<2;f++){ int A[6] = {a,b,c,d,e,f}; for(int i=0;i<5;i++){ for(int j=0;j<6;j++) res[i][j]=0; } for(int i=0;i<5;i++) { for(int j=0;j<6;j++){ temp[i][j]=Matrix[i][j]; }//循環copy } for(int i=0;i<6;i++){//依照枚舉數組將第一排按下 if(A[i]==1){ res[0][i]=1; switch (i){ case 0: Flip(temp[0][i]); Flip(temp[0][i+1]); Flip(temp[1][i]); break; case 5: Flip(temp[0][i]); Flip(temp[0][i-1]); Flip(temp[1][i]); break; default: Flip(temp[0][i]); Flip(temp[0][i-1]); Flip(temp[0][i+1]); Flip(temp[1][i]); break; } } } for(int i=0;i<3;i++){//其餘數組依次往下按 for(int j=0;j<6;j++){ if(temp[i][j]==1){ res[i+1][j]=1; switch (j){ case 0: Flip(temp[i][j]); Flip(temp[i+1][j+1]); Flip(temp[i+1][j]); Flip(temp[i+2][j]); break; case 5: Flip(temp[i][j]); Flip(temp[i+1][j-1]); Flip(temp[i+1][j]); Flip(temp[i+2][j]); break; default: Flip(temp[i][j]); Flip(temp[i+1][j-1]); Flip(temp[i+1][j]); Flip(temp[i+1][j+1]); Flip(temp[i+2][j]); break; } } } } for(int i=0;i<6;i++){ if(temp[3][i]==1){ res[4][i]=1; switch (i){ case 0: Flip(temp[3][i]); Flip(temp[4][i+1]); Flip(temp[4][i]); break; case 5: Flip(temp[3][i]); Flip(temp[4][i-1]); Flip(temp[4][i]); break; default: Flip(temp[3][i]); Flip(temp[4][i-1]); Flip(temp[4][i+1]); Flip(temp[4][i]); break; } } } if(Check()){ print(t); } } } }
不過這題能夠利用二進制枚舉法進行簡化。
什麼是二進制枚舉法呢?
我在枚舉從000000~111111的時候,我嵌套了6層循環,若是使用二進制來表示這個數組,我只須要枚舉從0到31便可。
下面就是mooc老師寫的代碼。
#include <memory> #include <string> #include <cstring> #include <iostream> using namespace std; int GetBit(char c,int i) { //取c的第i位 return ( c >> i ) & 1; } void SetBit(char & c,int i, int v) { //設置c的第i位爲v if( v ) c |= ( 1 << i); else c &= ~( 1 << i); } void Flip(char & c, int i) { //將c的第i位爲取反 c ^= ( 1 << i); } void OutputResult(int t,char result[]) //輸出結果 { cout << "PUZZLE #" << t << endl; for( int i = 0;i < 5; ++i ) { for( int j = 0; j < 6; ++j ) { cout << GetBit(result[i],j); if( j < 5 ) cout << " "; } cout << endl; } } int main() { char oriLights[5]; //最初燈矩陣,一個比特表示一盞燈 char lights[5]; //不停變化的燈矩陣 char result[5]; //結果開關矩陣 char switchs; //某一行的開關狀態 int T; cin >> T; for( int t = 1; t <= T; ++ t) { memset(oriLights,0,sizeof(oriLights)); for( int i = 0;i < 5; i ++ ) { //讀入最初燈狀態 for( int j = 0; j < 6; j ++ ) { int s; cin >> s; SetBit(oriLights[i],j,s); } } for( int n = 0; n < 64; ++n ) { //遍歷首行開關的64種狀態 memcpy(lights,oriLights,sizeof(oriLights)); switchs = n; //第i行的開關狀態 for( int i = 0;i < 5; ++i ) { result[i] = switchs; //第i行的開關方案 for( int j = 0; j < 6; ++j ) { if( GetBit(switchs,j)) { if( j > 0) Flip(lights[i],j-1);//改左燈 Flip(lights[i],j);//改開關位置的燈 if( j < 5 ) Flip(lights[i],j+1);//改右燈 } } if( i < 4 ) lights[i+1] ^= switchs;//改下一行的燈 switchs = lights[i]; //第i+1行開關方案和第i行燈狀況同 } if( lights[4] == 0 ) { OutputResult(t,result); break; } } // for( int n = 0; n < 64; n ++ ) } return 0; }
PS:這手二進制枚舉秀到我了。