@[TOC]算法实战总结——暴力解决法
#算法实战总结——暴力解决法
在家里准备竞赛的同时也想把自己最近学习到的东西每次学习进行一个总结,新人初学算法,有不对的地方希望各位大佬们能够指正。
理论背景:递归调用和穷举搜索法
1递归调用:
我自己对递归的理解就是不断地调用自身先由上而下递进,一般问题可能直接找到问题的出口就能够解决,但是像很多计算问题解得个数的问题就需要再向上回溯,是否能够运用递归的方法取决于问题的性质。一般如果一个复杂问题可以不断分解成多个相同简单的问题并且只要解决其中的一个小问题就可以得出所有问题的解,就可以利用递归来解决。递归调用是实现穷举搜索的强大工具
2穷举搜索法:
穷举搜索法就是找出所有问题的解,但在穷举时我们要时刻注意一个问题,就是重复,不同的问题产生的重复是不同要想解决重复,就要找到重复发生的地方,在下面会有这样的例题
例题1:串串字连环:
利用5*5大小的英文字母格子进行的游戏。规则是:连接上下左右、对角线方向上相邻的字母,组成一个单词。
代码如下:
#include<iostream>
#include<string>
using namespace std;
char board[5][5];
string boar = { "URLPMXPRETGIAETXTNZYXOQPS" };
int dx[8] = { -1,-1,-1,1,1,1,0,0 };
int dy[8] = { -1,0,1,-1,0,1,-1,1 };
void fuzhi()
{
int k = 0;
int i = 0;
for (i = 0; i < 5; i++) {
for (int y = 0; y < 5; y++) {
board[i][y] = boar[k];
k++;
}
}
}
bool inRange(int x, int y)
{
int size = 25;
size = sqrt(size);
if (x < size && y < size)
{
return true;
}
return false;
}
bool hasword(int x, int y, string& word)
{
int nextx;
int nexty;
if (!inRange(x, y))
{
return false;
}
if (board[x][y]!= word[0])
{
return false;
}
if (word.size() == 1)
{
return true;
}
for (int der = 0; der < 8; der++)
{
nextx = x + dx[der];
nexty = y + dy[der];
word = word.substr(1);
if (hasword(nextx, nexty, word))
return true;
}
return false;
}
int main()
{
fuzhi();
string word;
cout << "请输入字符串\n";
cin >> word;
bool tag;
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 5; j++)
{
cout << board[i][j] + " ";
}
cout << "\n";
}
tag=hasword(2, 0, word);
if (tag)
{
cout << "find it\n";
}
else
{
cout << "error\n";
}
return 0;
}
例题2:郊游问题:
给定出去郊游的学生人数和郊游学生之间的关系(是否为朋友),规定两人组成一个小队,只有是朋友关系的两个人才能组成一组,找出所有的组队方法;
输入:
学生人数n,
朋友关系对数m;
下一行输入m对具有朋友关系的学生编号(将学生分别编号为1-n)
输出:
学生可配对的总数;
输入案例:
4
6
0 1 1 2 2 3 3 0 0 2 1 3
输出案例:
3
注意:
此题会出现前面提到的重复,重复的原因和解决的方法都在代码的注释中
#include<iostream>
using namespace std;
int n;
bool arefriends[10][10];
int countfriends(bool take[10])
{
int i = 0;
int frist=-1;
bool flag = true;
for (i = 0; i < n; i++)
{
if (!take[i])
{
frist = i;
flag = false;
break;
}
}
if (frist==-1)
return 1;
int ret = 0;
for (i = frist+1; i < n; i++)//利用frist变量每次先给排名靠前的学生组队就可以解决重复。
{
if (!take[i] && !take[frist] && arefriends[i][frist])
{
take[i] = take[frist] = true;
ret += countfriends(take);
take[i] = take[frist] = false;//递归向下结束后回复原来的状态以便于进行其他的分支,利用for循环进行分支查询
//也可以手写进行分支的查询,比如分形图
}
}
return ret;
}
void fuzhi(int a[], int b[],int m)
{
int i = 0, j = 0;
for (i = 0; i < n; i++)
{
for (j = 0; j < n; j++)
{
arefriends[i][j] = false;
}
}
int k = 0;
j = 0;
for (int i = 0; i < m; i++)
{
k = a[i];
j = b[i];
arefriends[k][j] = true;
arefriends[j][k] = true;//只保存一个三角
}
for (i = 0; i < n; i++)
{
for (j = 0; j < n; j++)
{
cout << " " << arefriends[i][j];
}
cout << "\n";
}
}
int main()
{
cout << "请输入人数:\n";
cin >> n;
cout << "请输入朋友关系对数:\n";
int m = 0;
cin >> m;
cout << "请输入朋友关系:\n";
int a[10];
int b[10];
for (int i = 0; i < m; i++)
{
cin >> a[i] >> b[i];
}
fuzhi(a, b, m);
bool take[10];
for (int i = 0; i < n; i++)
{
take[i] = false;
}
int count = 0;
count = countfriends(take);
cout << "\n" << count;
}
/*
上述代码产生重复,原因:
1:同一组合如(0 1),(1 0),当做不同的排列;
2:将同一组合的序列颠倒当做同一排列
上述两种重复会产生指数幂的乘积作为结果
解决:
1:在存储朋友关系时只存储上三角或者下三角—>解决第一种情况;
或者直接在剩余学生中查找序号靠前的;
*/
例题3盖板游戏:
有一个H*W大小的游戏板,由黑白两种单位格子组成,现在要用3个单位格子的L形状板块把白色格子盖住,板块可以自由旋转,但不能重叠,覆盖黑色格子,或者超出游戏板,找出给定板后有几种覆盖的方法;
重复:
这里面避免重复的方法就是每次选择最左上角的格子进行覆盖,和上面的郊游类似。还有就是,如果的编译器保留堆栈不够大的话,会出现溢出现像,只需要修改一下编译器的保留堆栈就可以(我溢出了,百度这么说,我也改了,然而并没有卵用,还是会溢出,检查了几遍代码没有找出问题。。)测试案例在代码中有
代码:
#include<iostream>
#include<vector>
#define N 8
#define M 10
using namespace std;
//可以盖板的几种方式;
const int covertype[4][3][2] =
{
{{0,0},{1,0},{0,1}},
{{0,0},{0,1},{1,1}},
{{0,0},{1,0},{1,1}},
{{0,0},{1,0},{1,-1}}
};
void creat(vector<vector<int> >& board)
{
int i = 0, j = 0;
for (i = 0; i < N; i++)
{
for (j = 0; j < M; j++)
{
if (i == 0||i==N-1)
{
board[i][j] = 1;
}
else
{
if (j == 0 || j == M - 1)
{
board[i][j] = 1;
}
else
{
board[i][j] = 0;
}
}
}
}
}
//判断是否可以盖板
bool set(vector<vector<int> >& board, int x, int y, int type, int delate)
{
bool flag = true;
for (int i = 0; i < 3; i++)
{
const int nx = x + covertype[type][i][0];
const int ny = y + covertype[type][i][1];
if (nx < 0 || nx >= board.size() || ny < 0 || ny >= board[0].size())
{
flag = false;
}
else
{
if (board[nx][ny]+=delate > 1)
{
flag = false;
}
}
}
return flag;
}
//寻找下一个白色格子
int cover(vector<vector<int> >& board)
{
int x = -1, y = -1;
int i = 0, j = 0;
for (i = 0; i < board.size(); i++)
{
for (j = 0; j < board[i].size(); j++)
{
if (board[i][j] == 0)
{
x = i;
y = j;
break;
}
}
if (y != -1)
{
break;
}
}
if (y == -1)
{
return 1;
}
int ret=0;
for (int type = 0; type < 3; type++)
{
if (set(board, x, y, type, 1))
{
ret += cover(board);
}
//删除覆盖的板
set(board, x, y, type, -1);
}
return ret;
}
int main()
{
int i = 0, j = 0;
vector<vector<int> > board(N, vector<int>(M));
creat(board);
for (i = 0; i < board.size(); i++)
{
for (j = 0; j < board[i].size(); j++)
{
cout << board[i][j] << " ";
}
cout << "\n";
}
int count = 0;
count = cover(board);
cout << count << endl;
}