目录
算法简介:
枚举方式:
1.每一个数都有两种状态,也就是选或不选,时间复杂度也就是2^n,每一个数都有选和不选两种状态。
2.生成给定集合所有可能排列的方法,与之不同的是同样是1 2 3三个数字,1,2, 3和 1,3,2是两种方案。
3.不考虑元素的顺序。也就是 1 2 3 和 1 3 2是同一种方案
图的搜索:
奶牛和草丛
题目描述
输入
输出
样例输入
样例输出
解题步骤:
解题代码:
练习:
洛谷P1219 [USACO1.5] 八皇后 Checker Challenge
题目描述
输入格式
输出格式
留下你的足迹吧!谢谢。
算法简介:
DFS算法的基本思想是从图中的某个顶点v出发,访问此顶点,然后依次从v的未被访问的邻接点出发深度优先遍历图,直至图中所有和v有路径相通的顶点都被访问到。若此时图中尚有顶点未被访问,则另选图中一个未曾被访问的顶点作起始点,重复上述过程,整个进程反复进行直到所有顶点都被访问为止。
枚举方式:
1.每一个数都有两种状态,也就是选或不选,时间复杂度也就是2^n,每一个数都有选和不选两种状态。
代码实现:
#include<bits/stdc++.h>
using namespace std;
int n;
int vis[20];
void dfs(int x){if(x>n){for(int i=1;i<=n;i++){if(vis[i]==1)cout<<i<<" ";}cout<<'\n';return;}vis[x]=-1;dfs(x+1);vis[x]=0;vis[x]=1;dfs(x+1);vis[x]=0;
}
int main(){cin>>n;dfs(1);return 0;
}
2.生成给定集合所有可能排列的方法,与之不同的是同样是1 2 3三个数字,1,2, 3和 1,3,2是两种方案。
代码实现:
for(int i=1;i<=n;i++){if(!vis[i]){vis[i]=1;//选过标记a[x]=i;//表示被选dfs(x+1);//继续选下一个vis[i]=0;//回溯重置a[x]=0;}}
3.不考虑元素的顺序。也就是 1 2 3 和 1 3 2是同一种方案
代码实现:
for(int i=u;i<=n;i++){a[x]=i;dfs(x+1,i+1);//选下一个数字,从i+1开始往后选a[x]=0;}
图的搜索:
以下题举例:
奶牛和草丛
题目描述
奶牛Bessie计划好好享受柔软的春季新草。新草分布在R行C列的牧场里。它想计算一下牧场中的草丛数量。
在牧场地图中,每个草丛要么是单个“#”,要么是有公共边的相邻多个“#”。给定牧场地图,计算有多少个草丛。
例如,考虑如下5行6列的牧场地图
.#....
..#...
..#..#
....##
.....#
这个牧场有3个草丛:一个在第一行,一个在第二列横跨了二、三行,一个在第三行横跨了三、四、五行。
输入
第一行包含两个整数R和C,中间用单个空格隔开。
接下来R行,每行C个字符,描述牧场地图。字符只有“#”或“.”两种。(1 <= R, C <= 100 )
输出
输出一个整数,表示草丛数。
样例输入
5 6
.#....
..#...
..#..#
....##
.....#
样例输出
3
这是一题典型的dfs,
解题步骤:
1.选择起始点:从图的某个顶点u开始。
2.标记当前顶点:将当前顶点u标记为已访问,以避免重复访问。
3.遍历邻接点:对于u的每个未访问的邻接点v,递归地执行dfs,从v开始。
4.回溯:当没有更多的邻接点可以遍历时,返回到上一步的顶点。
解题代码:
#include<bits/stdc++.h>
using namespace std;
int m,n,c;
char a[105][105];
int b[105][105];
void f(int x,int y){if(x>=1&&x<=m&&y>=1&&y<=n){if(a[x][y]=='#'&&b[x][y]==0){//是草丛,且没被遍历b[x][y]=1;//搜四个方向f(x+1,y);f(x-1,y);f(x,y+1);f(x,y-1);}}else return;//不符条件,回溯。
}
int main(){cin>>m>>n;//输入for(int i=1;i<=m;i++){for(int j=1;j<=n;j++){cin>>a[i][j];}}//遍历查找for(int i=1;i<=m;i++){for(int j=1;j<=n;j++){if(a[i][j]=='#'&&b[i][j]==0){c++;f(i,j);}}}cout<<c;return 0;
}
练习:
洛谷P1219 [USACO1.5] 八皇后 Checker Challenge
题目描述
一个如下的 6×66×6 的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行、每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子。
上面的布局可以用序列 2 4 6 1 3 5 来描述,第 i 个数字表示在第 i 行的相应位置有一个棋子,如下:
行号 1 2 3 4 5 6
列号 2 4 6 1 3 5
这只是棋子放置的一个解。请编一个程序找出所有棋子放置的解。
并把它们以上面的序列方法输出,解按字典顺序排列。
请输出前 3 个解。最后一行是解的总个数。
输入格式
一行一个正整数 n,表示棋盘是 n×n 大小的。
输出格式
前三行为前三个解,每个解的两个数字之间用一个空格隔开。第四行只有一个数字,表示解的总数。
#include<bits/stdc++.h>
using namespace std;
int n,vx[15],vy[15],v1[30],v2[30],a[15],c;
void f(int i){if(i>n){c++;if(c<=3){for(int k=1;k<=n;k++)cout<<a[k]<<" ";cout<<endl;}return;}for(int j=1;j<=n;j++){if(!vx[i]&&!vy[j]&&!v1[i-j+n]&&!v2[i+j]){a[i]=j;vx[i]=1;vy[j]=1;v1[i-j+n]=1;v2[i+j]=1;f(i+1);vx[i]=0;vy[j]=0;v1[i-j+n]=0;v2[i+j]=0;}}
}
int main() {cin>>n;f(1);cout<<c;return 0;
}