一、何谓暴力法
暴力法,也叫穷举法。它要求设计者找出所有可能的方法,然后选择其中的一种方法,若该方法不可行则试探下一种可能的方法。该方法逻辑清晰、简单,编写程序简洁。在某些情况下,算法规模不大时,使用优化的算法没有必要,而且某些优化算法本身较为复杂,在规模不大时可能因为复杂的算法浪费时间,反而不如简单的蛮力搜索。使用暴力法的几种情况:
- 搜索所有的解空间和路径;2. 直接进行计算;3. 在问题规模不是很大的情况下,现实问题的模拟与仿真。
二、搜索所有的路径和解空间
使用暴力方法将所有的可能解列出来,看这些解是否满足要求或者条件,从中选择出符合要求的解。
例1:Safecracker
这个题目可以用暴力法解决,只需要测试满足的解即可。值得注意的是需要考虑取值范围和多解时候的情况。代码与ZLG的差不多。
1 #include <iostream> 2 #include <string> 3 #include <algorithm> 4 5 using namespace std; 6 string str; 7 8 bool cmp (int i,int j) { return (i>j);} 9 10 int cal(int y, int w, int v, int x, int z) 11 { 12 v -= 64, w -= 64, x -= 64, y -= 64, z -= 64; 13 return (v - w*w + x*x*x - y*y*y*y + z*z*z*z*z); 14 } 15 16 bool GetSol(int t, string s){ 17 int len; 18 int max, min; 19 len = s.length(); 20 min = cal(s[0],s[1],s[len-3],s[len-2],s[len-1]); 21 max = cal(s[len-1],s[len-2],s[2],s[1],s[0]); 22 if( t> max && t < min) 23 return false; //no solutions 24 25 int vis[len]; 26 for(int i = 0; i < len; i++) vis[i] = 0; 27 28 for(int a=0; a<len; a++){ 29 vis[a] = 1; 30 for(int b=0; b<len; b++){ 31 if(!vis[b]){ 32 vis[b] = 1; 33 for(int c=0; c<len; c++){ 34 if(!vis[c]){ 35 vis[c] = 1; 36 for(int d=0; d<len; d++){ 37 if(!vis[d]){ 38 vis[d] = 1; 39 for(int e=0; e<len; e++){ 40 if(!vis[e] && t == cal(s[d], s[b], s[a], s[c], s[e])){ 41 cout <<s[a]<<s[b]<<s[c]<<s[d]<<s[e]<<endl; 42 return true; 43 } 44 } 45 vis[d] =0; 46 } 47 } 48 vis[c] = 0; 49 } 50 } 51 vis[b] = 0; 52 } 53 } 54 vis[a] = 0; 55 } 56 return false; 57 } 58 59 int main(int argc, char *argv[]) 60 { 61 int t; 62 bool flag; 63 while(cin>>t && cin>>str){ 64 if(t==0 && str=="END") break; 65 66 sort(str.begin(),str.end(),cmp); //排序 67 flag = GetSol(t, str); 68 69 if(!flag) 70 cout <<"no solution"<<endl; 71 } 72 73 74 return 0; 75 }
三、枚举所有的情况
这个题目可以将所有的情况例举一次,然后去判断。另外注意2^x可能会超出long long类型,又因为2×s mod n = 2x (s mod n),因此所写的程序如下:
1 #include <iostream> 2 3 using namespace std; 4 5 int main(int argc, char *argv[]) 6 { 7 int n,flag; 8 long s; 9 10 while(cin>>n){ 11 flag =0; 12 s=1; 13 for(int x=1;x<n+1;x++){ 14 s *= 2; 15 s %= n; 16 if(s == 1){ 17 flag = x; 18 break; 19 } 20 } 21 if(flag!=0) 22 cout<<"2^"<<flag<<" mod "<<n<<" = 1"<<endl; 23 else 24 cout<<"2^?"<<" mod "<<n<<" = 1"<<endl; 25 } 26 27 return 0; 28 }
另外一种枚举的写法:
#include<stdio.h> int main(void) { int n; while(~scanf("%d",&n)){ if(n == 1 || n % 2 == 0){ printf("2^? mod %d = 1\n", n); continue; } int k = 1, ans = 2; while(ans != 1){ ans = ans *2 % n; k++; } printf("2^%d mod %d = 1\n", k, n); } return 0; }
例3: Fibonacci Again
这个题目实际上去枚举情况: 第一步不是直接计算,而是寻找规律,第二步在规律中枚举所有的情况即可。代码如下:
1 #include <iostream> 2 3 using namespace std; 4 5 int main(){ 6 long n; 7 while(cin>>n){ 8 if(n%8==2 || n%8==6) 9 cout << "yes" << endl; 10 else 11 cout << "no" << endl; 12 } 13 return 0; 14 }
三、直接计算
例4:Big Number
这个题目主要利用log10的函数来直接计算就好。代码如下:
1 #include <iostream> 2 #include <math.h> 3 4 using namespace std; 5 6 int main(){ 7 8 int testCase, n; 9 double sum; 10 cin >> testCase; 11 while(testCase--){ 12 cin >> n; 13 sum = 0; 14 for(int i=1; i<=n; i++){ 15 sum += log10(i); 16 } 17 cout << (int)sum+1 <<endl; 18 } 19 20 return 0; 21 }
四:模拟与仿真
例5:Buildings
这个可以算水题,将输入的东西进行判断是否为1,如果为1的话就可以累加。代码如下:
1 #include <iostream> 2 3 using namespace std; 4 5 int main(int argc, char *argv[]) 6 { 7 int T,n,m, k, ans; 8 cin >> T; 9 10 while(T--){ 11 cin >>n >>m; 12 ans = 0; 13 for(int i=0; i<n; i++){ 14 for(int j=0; j<m; j++){ 15 cin >> k; 16 if(k) ans++; 17 } 18 } 19 cout << ans <<endl; 20 } 21 return 0; 22 }
这个当习题。