P3625
#include <iostream>
using namespace std;
int n, m;
int d1[]={1,-1,0,0};
int d2[]={0,0,1,-1};
const int N=110;
int p[N][N];
int st[N][N];
int FLAG;
void dfs(int x, int y){
if(x==n && y==m) {FLAG=1; return;}
//上下左右搜索 如果走到头了就回去 什么事走到头了 就是四个循环全都用完了 函数过完了 这时候回溯
for(int i=0; i<4; i++){
int xx=x+d1[i];
int yy=y+d2[i];
if(!st[xx][yy] && xx>=1 && xx<=n && yy>=1 && yy<=n){
//if(st[xx][yy]) return;
st[xx][yy]=1; //
dfs(xx, yy);
}
}
return;
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
char c;
cin>>c;
if(c=='#') st[i][j]=1;
}
}
dfs(1, 1);
if(FLAG) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
return 0;
}
P1706:
举个例子:
1 -> 2 ->3 (1 12 123) 回到 12找可不可以有别的情况 这时候3由于被标记而知道已经用完了
12这一层分支及以下搜索完了 就返回 1 这时候3的标记需要重新变为0 因为1->3这种情况也需要考虑
#include <iostream>
using namespace std;
const int N=10;
int n;
int path[N]; //存下来状态
bool st[N]; //当前位置上已经有哪些被用过了
void dfs(int u){
if(u==n){
for(int i=0; i<n; i++){
printf(" %d",path[i]); //如果是已经到了最后一位数了就只用把path里面已经定好的路径输出就可以了
}
printf("\n");
return;
}
for(int i=1;i<=n;i++){
if(!st[i]){ //找到一个没有被用过的数
path[u]=i; //这一层i没有用过所以存到path[u]里面
st[i]=1; //用完了之后就标记为真 将要走到下一层下一层不可以用了哦 直到return 一切结束
dfs(u+1); //递归下一层的
st[i]=0; //递归完了 回来恢复现场 因为上面的那个相邻的分支还要用
}
}
}
int main(){
cin>>n;
dfs(0);
return 0;
}
P1451
一个一个遍历找到联通块入口 搜索整个联通块 边搜索边标记
#include <iostream>
#include <string.h>
using namespace std;
const int N=105;
int n, m, ans;
int st[N][N], g[N][N];
int d1[]={1,-1,0,0};
int d2[]={0,0,1,-1};
void dfs(int x, int y){ //从某个结点开始把联通块里面的全都搜索标记一遍
st[x][y]=1; //接下来进行分支操作
for(int i=0;i<4;i++){
int xx=x+d1[i];
int yy=y+d2[i];
if(st[xx][yy] || g[xx][yy]==0) continue; //如果已经走过了或者走到0了 跳出循环 到下一个分支
dfs(xx, yy); //可以作为分支的再作为结点递归
}
}
int main(){
cin>>n>>m;
memset(g,0,sizeof g);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%1d", &g[i][j]); //只读一位 也可用字符串读入 一连串数据没有空格不可以直接读入
// cout<<g[i][j]<<' ';
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(st[i][j]==0 && g[i][j]!=0){ //dfs的作用主要是标记那些不为0而且已经搜索过的数
dfs(i,j);
ans++;
}
}
}
cout<<ans<<endl;
return 0;
}
P1219
思路:
因为有不同行不同列的要求,次问题可以当做排列组合数考虑,当然对角线要单独考虑。
用两个数组表示正副对角线集合(以左上角为原点)。正对角线为了防止下标为负,就加了个n
注意N的范围
#include <iostream>
using namespace std;
const int N=30;
int path[N];
int st[N], dg[N], udg[N];
int cnt=0;
int n;
void dfs(int u){
if(u>n){ //
cnt++;
if(cnt<=3){
for(int k=1;k<=n;k++) cout<<path[k]<<' ';
cout<<endl;
return;
}
else return;
}
for(int i=1;i<=n;i++){
if(!st[i] && !dg[i+u] && !udg[n-i+u])
{
st[i]=dg[i+u]=udg[n-i+u]=1;
path[u]=i;
dfs(u+1);
st[i]=dg[i+u]=udg[n-i+u]=0;
}
}
}
int main(){
cin>>n;
dfs(1);
cout<<cnt;
return 0;
}