在算法竞赛中,很多问题是来不及用数学公式推导出来的。或者说根本就找不到数学规律,这时我们就需要使用枚举来暴力破解。

不过枚举也是需要脑子的,一味的暴力只能超时。因此我这里选择了几道mooc上经典的题目来做复习。

1、完美立方。

  思路:

  从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=;a<=N;a++){
for(int d=;d<=a;d++){
for(int c=;c<=d;c++){
for(int b=;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 ;
}

运行结果如下:

2、生理周期

做此题我们首先会有个思路就是从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=;
while(cin >> p >> e >> i >> d&&p!=-) {
int k;
for(k=d+;(k-p)%||(k-e)%||(k-i)%;k++);
cout<<"Case "<<++N<<": The next triple peak occurs in "<<k-d<<" days."<<endl;
}
return ;
}
不过在此我们是否会有个疑问。一个一个的尝试是否过于浪费时间了?
这里我们给出另一种思路。
我们先枚举出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=;
while(cin >> p >> e >> i >> d&&p!=-) {
int k;
for(k=d+;(k-p)%;k++);//c++中正数就是true
for(;(k-e)%;k+=);
for(;(k-i)%;k+=*);
cout<<"Case "<<++N<<": The next triple peak occurs in "<<k-d<<" days."<<endl;
}
return ;
}

运行结果如下。

3、POJ1013 Counterfeit Dollar(mooc中称硬币)

题目链接

 这题目不难,但是这道题我WA了很多次。其中我说下WA的原因:

1.每个盘子称的牌子不一定有4个。

2.如果某个假币可能轻可能重,不要continue,要以heavy----light的俩次形式输出。

思路:

定义一个大小为9字符串数组。作为每次输入的字符串。

依次假设每个硬币为假的。然后从重到轻挨个枚举,当找到假币的时候输出。

下面是AC代码:

#include <iostream>
#include <string>
#include <map> using namespace std;
int main(){
int N;
cin>>N;
map<char,int> m;
for(int i=;i<;i++) {
m[(char)i]=;
}
while(N--){
string str[];
cin>>str[]>>str[]>>str[]>>str[]>>str[]>>str[]>>str[]>>str[]>>str[];
for(int i=;i<;i++){
int sign = ;
int left = ,right = ;
string res="";
m[(char)i]=;
for(int k=;k<;k++) {
for (int j = ; j < str[+*k].length(); j++)left += m[str[+*k][j]];
for (int j = ; j < str[+*k].length(); j++)right += m[str[+*k][j]];
if (left == right) res = "even";
if (left > right) res = "up";
if (left < right) res = "down";
if (res == str[+*k])sign++;
left=;
right=;
}
if(sign==)cout<<(char)i<<" is the counterfeit coin and it is heavy.\n"; sign=;
res="";
m[(char)i]=-;
for(int k=;k<;k++) {
for (int j = ; j < str[+*k].length(); j++)left += m[str[+*k][j]];
for (int j = ; j < str[+*k].length(); j++)right += m[str[+*k][j]];
if (left == right) res = "even";
if (left > right) res = "up";
if (left < right) res = "down";
if (res == str[+*k])sign++;
left=;
right=;
}
if(sign==) cout<<(char)i<<" is the counterfeit coin and it is light.\n"; m[(char)i]=;
}
}
return ;
}

4、EXTENDED LIGHTS OUT(POJ 1222)

题目链接

这道题着实有点难。不过我们这次用枚举的方法解答这个问题。

分析:

输入一个5*6的矩阵,让我们从中选取一个按钮方案,使最终所有灯都熄灭。

思路:

0、目标使所有灯的状态变为0。

1、想不干扰第1行别的灯的状态来改变第1行,就需要按下面的按钮才能准确的改变。

2、别的行数也是以此类推。

3、这样别的行数的状态都会随着第一行的变化而确定。

AC代码如下:

#include <iostream>
using namespace std;
int Matrix[][];
int res[][];
int temp[][];
void Flip(int &a){
if(a) a=;
else a=;
}
bool Check(){
for(int i=;i<;i++){
if(temp[][i]) return false;
}
return true;
}
void print(int t){
cout<<"PUZZLE #"<<t<<endl;
for(int i=;i<;i++){
for(int j=;j<;j++) {
if(j==)cout<<res[i][j];
else cout << res[i][j] << " ";
}
cout<<endl;
}
}
int main(){
int N;cin>>N;
for(int t=;t<=N;t++){
for(int i=;i<;i++)for(int j=;j<;j++)cin>>Matrix[i][j];//输入矩阵
for(int a=;a<;a++)for(int b=;b<;b++)for(int c=;c<;c++)for(int d=;d<;d++)for(int e=;e<;e++)for(int f=;f<;f++){
int A[] = {a,b,c,d,e,f};
for(int i=;i<;i++){
for(int j=;j<;j++) res[i][j]=;
}
for(int i=;i<;i++) {
for(int j=;j<;j++){
temp[i][j]=Matrix[i][j];
}//循环copy
}
for(int i=;i<;i++){//依照枚举数组将第一排按下
if(A[i]==){
res[][i]=;
switch (i){
case :
Flip(temp[][i]);
Flip(temp[][i+]);
Flip(temp[][i]);
break;
case :
Flip(temp[][i]);
Flip(temp[][i-]);
Flip(temp[][i]);
break;
default:
Flip(temp[][i]);
Flip(temp[][i-]);
Flip(temp[][i+]);
Flip(temp[][i]);
break;
}
}
}
for(int i=;i<;i++){//其他数组依次往下按
for(int j=;j<;j++){
if(temp[i][j]==){
res[i+][j]=;
switch (j){
case :
Flip(temp[i][j]);
Flip(temp[i+][j+]);
Flip(temp[i+][j]);
Flip(temp[i+][j]);
break;
case :
Flip(temp[i][j]);
Flip(temp[i+][j-]);
Flip(temp[i+][j]);
Flip(temp[i+][j]);
break;
default:
Flip(temp[i][j]);
Flip(temp[i+][j-]);
Flip(temp[i+][j]);
Flip(temp[i+][j+]);
Flip(temp[i+][j]);
break;
}
}
}
}
for(int i=;i<;i++){
if(temp[][i]==){
res[][i]=;
switch (i){
case :
Flip(temp[][i]);
Flip(temp[][i+]);
Flip(temp[][i]);
break;
case :
Flip(temp[][i]);
Flip(temp[][i-]);
Flip(temp[][i]);
break;
default:
Flip(temp[][i]);
Flip(temp[][i-]);
Flip(temp[][i+]);
Flip(temp[][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 ) & ;
}
void SetBit(char & c,int i, int v) {
//设置c的第i位为v
if( v )
c |= ( << i);
else
c &= ~( << i);
}
void Flip(char & c, int i) {
//将c的第i位为取反
c ^= ( << i);
}
void OutputResult(int t,char result[]) //输出结果
{
cout << "PUZZLE #" << t << endl;
for( int i = ;i < ; ++i ) {
for( int j = ; j < ; ++j ) {
cout << GetBit(result[i],j);
if( j < )
cout << " ";
}
cout << endl;
}
}
int main() {
char oriLights[]; //最初灯矩阵,一个比特表示一盏灯
char lights[]; //不停变化的灯矩阵
char result[]; //结果开关矩阵
char switchs; //某一行的开关状态
int T;
cin >> T;
for( int t = ; t <= T; ++ t) {
memset(oriLights,,sizeof(oriLights));
for( int i = ;i < ; i ++ ) { //读入最初灯状态
for( int j = ; j < ; j ++ ) {
int s;
cin >> s;
SetBit(oriLights[i],j,s);
}
}
for( int n = ; n < ; ++n ) { //遍历首行开关的64种状态
memcpy(lights,oriLights,sizeof(oriLights));
switchs = n; //第i行的开关状态
for( int i = ;i < ; ++i ) {
result[i] = switchs; //第i行的开关方案
for( int j = ; j < ; ++j ) {
if( GetBit(switchs,j)) {
if( j > )
Flip(lights[i],j-);//改左灯
Flip(lights[i],j);//改开关位置的灯
if( j < )
Flip(lights[i],j+);//改右灯
}
}
if( i < )
lights[i+] ^= switchs;//改下一行的灯
switchs = lights[i]; //第i+1行开关方案和第i行灯情况同
}
if( lights[] == ) {
OutputResult(t,result);
break;
}
} // for( int n = 0; n < 64; n ++ )
}
return ;
}

PS:这手二进制枚举秀到我了。

总结:暴力破解也不是很轻松。需要使用者对破解边界有足够的熟练度才行。

(BruteForce)暴力破解经典题目总结的更多相关文章

  1. 一道关于压缩包的ctf题目(包括暴力破解,明文攻击,伪加密)

    关于题目附件 链接:https://pan.baidu.com/s/1PRshlizSndkgxkslnqJrHA 提取码:p76e zip三连击 下载附件得到题目 手机号码一般是11位,那么我们设置 ...

  2. 利用base64库暴力破解base加密

    做个base加密题python语法出了一堆错误..... 附上py中关于base加密/解码的知识:http://www.open-open.com/lib/view/open1433990719973 ...

  3. 《11招玩转网络安全》之第三招:Web暴力破解-Low级别

    Docker中启动LocalDVWA容器,准备DVWA环境.在浏览器地址栏输入http://127.0.0.1,中打开DVWA靶机.自动跳转到了http://127.0.0.1/login.php登录 ...

  4. Metasploit 暴力破解演示

    本文简要演示使用Metasploit 中的mysql_login.postgresql_login.tomcat_mgr_login模块暴力破解Metasploitable 2 上部署的服务. Pre ...

  5. Brute Force(暴力(破解))

    一.攻击模块1:Brute Force(暴力破解) 暴力破解一般指穷举法,穷举法的基本思想是根据题目的部分条件确定答案的大致范围,并在此范围内对所有可能的情况逐一验证,直到全部情况验证完毕.若某个情况 ...

  6. UVa 11059 最大乘积 java 暴力破解

    题目链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_proble ...

  7. DVWA Brute Force:暴力破解篇

    DVWA Brute Force:暴力破解篇 前言 暴力破解是破解用户名密码的常用手段,主要是利用信息搜集得到有用信息来构造有针对性的弱口令字典,对网站进行爆破,以获取到用户的账号信息,有可能利用其权 ...

  8. burp暴力破解之md5和绕过验证码

    Burpsuite是一个功能强大的工具,也是一个比较复杂的工具 本节主要说明一下burp的intruder模块中的2个技巧 1.md5加密 我们在payload Processing中的add选项可以 ...

  9. 开源服务专题之------ssh防止暴力破解及fail2ban的使用方法

    15年出现的JAVA反序列化漏洞,另一个是redis配置不当导致机器入侵.只要redis是用root启动的并且未授权的话,就可以通过set方式直接写入一个authorized_keys到系统的/roo ...

随机推荐

  1. python爬虫集合

    逐渐也写了有二十余篇博文,内容一多就导致有些内容不能够方便快捷定位. 虽然博客有标签进行分类,实际查找时也并不如做一个同类文章的集合来得直观. 这里就对python爬虫相关博文做个集合: 爬虫基础知识 ...

  2. vscode设置让鼠标滚动改变字体大小

    打开settings.json文件 输入"editor.mouseWheelZoom": true, 这样比较方面,比默认的放大缩小来的快捷

  3. HDU 5238 Calculator 线段树 中国剩余定理

    题意: 给一个计算器,有一系列计算步骤,只有加,乘,幂三种运算. 有一种查询操作:查询初始值为\(x\)的时候,最终运算结果模\(29393\)的值. 有一种修改操作:可以修改第\(p\)个运算的运算 ...

  4. 深入Python底层,谈谈内存管理机制

    说到内存管理,就先说一下垃圾回收吧.垃圾回收是Python,Java等语言管理内存的一种方式,说的直白些,就是清除无用的垃圾对象.C语言及C++中,需要通过malloc来进行内存的申请,通过free而 ...

  5. python - 接口自动化测试 - contants - 常量封装

    # -*- coding:utf-8 -*- ''' @project: ApiAutoTest @author: Jimmy @file: contants.py @ide: PyCharm Com ...

  6. python - 目录处理

    # -*- coding:utf-8 -*- '''@project: jiaxy@author: Jimmy@file: study_文件目录操作.py@ide: PyCharm Community ...

  7. 【LeetCode】Binary Tree Preorder Traversal(二叉树的前序遍历)

    这道题是LeetCode里的第144道题. 题目要求: 给定一个二叉树,返回它的 前序 遍历. 示例: 输入: [1,null,2,3] 1 \ 2 / 3 输出: [1,2,3] 进阶: 递归算法很 ...

  8. js时间格式化工具,时间戳格式化,字符串转时间戳

    在开发中经常会用到时间格式化,有时候在网上搜索一大堆但不是自己想要的,自己总结一下,写一个时间格式化工具方便以后直接使用,欢迎大家来吐槽…… 1 2 3 4 5 6 7 8 9 10 11 12 13 ...

  9. TensorFlow——深入MNIST

    程序(有些不甚明白的地方改日修订): # _*_coding:utf-8_*_ import inputdata mnist = inputdata.read_data_sets('MNIST_dat ...

  10. The 2018 ACM-ICPC Asia Qingdao Regional Contest, Online

    A Live Love DreamGrid is playing the music game Live Love. He has just finished a song consisting of ...