问题描述:给你一个数字m,问1~m这几个数字有多少种排列方案,输出每一种排列方案。
解:这是一个全排列问题。解决这个问题可以采用深度优先搜索的思想,即先确定第一个位置的数字(将这个数字加入队列),在第一个数字确定的前提下,递归再确定第二个数字(将这个数字加入队列)……这样,直到确定第m个数字。这就是满足要求的方案中的一种,此时输出整个队列的数字,这也是递归的边界条件。下面给出C++实现代码:
#include
using namespace std;
bool vis[19];// 标记数组,用来标记当前数字是否可用
int qu[109];// 用来存储数字的队列
int cnt = 0;
// n代表当前是在确定第几个数字,m代表一共需要确定的数字的个数
void dfs(int n, int m){
// 递归的边界条件,当你处理的数字位数超过了m,输出队列并返回
if(n>m){
for(int i=0;i<cnt;i++)
cout<<qu[i]<<" ";
cout<<endl;
cnt--;
return ;
}
// 从1~m遍历,看看当前数字是不是可以使用
for(int i=1;i<=m;i++){
if(vis[i]){
// 如果这个数字可用,使用这个数字并将这个数字设置为不可用
vis[i] = false;
// 入队
qu[cnt++] = i;
// 在确定了当前数字后,递归调用自己,来确定下一个数字
dfs(n+1, m);
/*
这里非常重要,也最不好理解,在后面的数字确定了之后,
开始返回,此时需要把当前这个数字重新置为true,表示可用。
举个例子,假设m为4,第一次输出的队列为1234,如果在函数返回
时,不将4重新置为true,则不会出现1243这种方案,最终结果就
错了。
*/
vis[i] = true;
}
}
cnt--;
}
int main(){
int m;
// 初始标记数组全设置为true
for(int i=0;i<19;i++)
vis[i] = true;
cin>>m;
dfs(1, m);
return 0;
}
问题描述:给你一个有序数组,再给你一个数x,问x是否在这个数组中。
解:实际上,二分搜索的思路是很好理解的。问题的关键在于确保这个数组是有序的(如果可以排序的话即使输入时乱序也没有关系)。在确保数组有序的前提下,我们就可以采用每次比较数组索引中位数和x来缩小解的范围。举个栗子,加入你在玩猜数字游戏,告诉你答案在一到十之间,实际上答案是3,让你猜。你最好的策略就是第一次猜5,告诉你猜大了,之后猜3……也就是每次猜最中间的那个数,这样即使不对,也可以缩小一半的可能区间。因此,如果数组长度是n的话,你最次log2(n)次就一定能得到答案。因此,二分搜索的时间复杂度就是log2(n)。下面给出二分搜索的C++实现代码:
#include
#include
using namespace std;
int num[1009];
int main(){
int n, x;
bool flag = false;
// 输入n个数字
cin>>n;
for(int i=0;i<n;i++)
cin>>num[i];
sort(num, num+n);
// 输入要判断的数字x
cin>>x;
// 进行二分搜索
int l = 0;// 左指针
int r = n-1;// 右指针
// 当左指针大于右指针时就没有必要再进行判断了
while(l<=r){
int mid = (l + r) / 2;
if(x > num[mid])
l = mid + 1;
else if(x < num[mid])
r = mid - 1;
else{
cout<<"找到了数字"<<x<<"!"<<endl;
flag = true;
break;
}
}
if(!flag)
cout<<"对不起,未找到数字"<<x<<"!"<<endl;
return 0;
}
问题描述:给你一个棋盘,其中有一个特殊点(一个小方块),希望你用三个小方块组成的骨牌覆盖这个棋盘。
解:对于这个问题,我们的策略是首先将棋盘分成四个相同的小棋盘,对称分割。之后,对其中没有特殊点的其他三个小棋盘放置骨牌,只需要在最中间放置一个骨牌就可以覆盖三个棋盘。
再然后,递归处理这四个小棋盘就可以了。用这种策略,我们不断缩小了问题的范围(棋盘的大小),直到最终棋盘只有一个格子大小就覆盖完成了。我们用相同的数字标记棋盘上的三个格子来代表一块骨牌的覆盖。C++实现代码如下:
#include
using namespace std;
int tile = 1;
int Board[1009][1009];
void ChessBoard(int tr, int tc, int dr, int dc, int Size){
if(Size == 1) return ;
int t = tile++, s = Size / 2;
if(dr < tr + s && dc < tc + s)
ChessBoard(tr, tc, dr, dc, s);
else{
Board[tr + s - 1][tc + s - 1] = t;
ChessBoard(tr, tc, tr + s - 1, tc + s -1, s);
}
if(dr < tr + s && dc >= tc + s)
ChessBoard(tr, tc + s, dr, dc, s);
else{
Board[tr + s - 1][tc + s] = t;
ChessBoard(tr, tc + s, tr + s - 1, tc + s, s);
}
if(dr >= tr + s && dc < tc + s)
ChessBoard(tr + s, tc, dr, dc, s);
else{
Board[tr + s][tc + s - 1] = t;
ChessBoard(tr + s, tc, tr + s, tc + s -1, s);
}
if(dr >= tr + s && dc >= tc + s)
ChessBoard(tr + s, tc + s, dr, dc, s);
else{
Board[tr + s][tc + s] = t;
ChessBoard(tr + s, tc + s, tr + s, tc + s, s);
}
}
int main(){
int tr, tc, dr, dc, Size;
cout<<"tr=";
cin>>tr;
cout<<"tc=";
cin>>tc;
cout<<"dr=";
cin>>dr;
cout<<"dc=";
cin>>dc;
cout<<"Size=";
cin>>Size;
ChessBoard(tr, tc, dr, dc, Size);
cout<<"棋盘覆盖成功!"<<endl;
for(int i=tr;i<tr+Size-1;i++){
for(int j=tc;j<tr+Size-1;j++){
cout<<Board[i][j];
}
cout<<endl;
}
return 0;
}
PS:此篇博客重点在于给出实现代码,对于问题的描述以及解题思路的讲解可能不够详细全面,敬请谅解。