DFS (排列数字+n-皇后)

 842. 排列数字 - AcWing题库

用dfs,求出全排列。

//下标从1开始的代码
#include<iostream>
using namespace std;
const int N=10;
int path[N];//路径记录
bool st[N];//判断数字是否已用过 用过为true 没用过false
int n;
void dfs(int u)
{
    if(u==n+1)//n位全搜完了 搜索完成
    {
        for(int i=1;i<=n;i++) printf("%d ",path[i]);//0~n记录每一个数
        printf("\n");
        return;
    }
    for(int i=1;i<=n;i++)//遍历看看哪些用过哪些没有用过
    {
        if(!st[i])//没有用过
        {
            path[u]=i;//赋值
            st[i]=true;//标记已用过
            dfs(u+1);//dfs下面一位
            st[i]=false;//恢复现场,标记未用过
        }
    }
}
int main()
{
    cin>>n;
    dfs(1);//从第一位开始向下搜索
    return 0;
}

843. n-皇后问题 - AcWing题库

解法一:

dfs按行搜索,把他看成排列问题,就是第一行,第二行……

//下标从1开始
#include<iostream>
using namespace std;
const int N=20;
char q[N][N];//q[][]用来记录皇后数组 下标从1开始
int n;
bool col[N],dg[N],udg[N];
//col[]列 dg[]副对角线(右上到左下) udg[]主对角线
void dfs(int x)
{
   if(x==n+1)//如果已经检测到n+1行,说明已经结束
   {
       //输出皇后数组中每一个元素,不可以puts,因为是从下标1开始
       for(int i=1;i<=n;i++)
       {
           for(int j=1;j<=n;j++)
                 printf("%c",q[i][j]);
             printf("\n");
       }
       printf("\n");    
       return;
   }
   for(int y=1;y<=n;y++)//x行y列
   {
       if(!col[y] && !dg[x+y] && !udg[y-x+n])//第y列和两条对角线都没有用过
       {
           q[x][y]='Q';//赋值为 'Q'
           col[y]=dg[x+y]=udg[y-x+n]=true;//true为用过
           dfs(x+1);//搜索下一个
           col[y]=dg[x+y]=udg[y-x+n]=false;//恢复现场
           q[x][y]='.';//恢复现场
       }
   }
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            q[i][j]='.';//全部初始化为.
    
    dfs(1);//从第一行开始dfs
    return 0;
    
}
//下标从0开始 AcWing代码
#include<iostream>
using namespace std;
const int N=20;
char q[N][N];
int n;
bool col[N],dg[N],udg[N];

void dfs(int x)
{
    if(x==n)
    {
        for(int i=0;i<n;i++) puts(q[i]);
        puts("");
        return;
    }
    
    for(int y=0;y<n;y++)
    {
        if(!col[y] && !dg[x+y] && !udg[y-x+n])
        {
            q[x][y]='Q';
            col[y]=dg[x+y]=udg[y-x+n]=true;
            dfs(x+1);
            q[x][y]='.';
            col[y]=dg[x+y]=udg[y-x+n]=false;
        }
    }
}

int main()
{
    cin>>n;
    
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            q[i][j]='.';
            
    dfs(0);
    
    return 0;
    
}

通过截距b来确定一条直线,x,y只要再同一条直线上,都会与b建立等式。

解法二:

按每一个点去判断能不能放

//下标从1开始
#include<iostream>
using namespace std;
const int N=20;
char q[N][N];//q[][]用来记录皇后数组 下标从1开始
int n;
bool row[N],col[N],dg[N],udg[N];
//row[]行 col[]列 dg[],udg[]两条对角线
void dfs(int x,int y,int s)//x横坐标 y纵坐标 s皇后个数
{
    if(y==n+1) y=1,x++;//一行中每一列都遍历过了 到下一行第一列
    if(x==n+1)//行都遍历完
    {
        if(s==n)//皇后个数等于n
        {
            for(int i=1;i<=n;i++)
            {
                for(int j=1;j<=n;j++)
                    printf("%c",q[i][j]);
                printf("\n");
            }
            printf("\n");
        }
       return;
    }
    
    dfs(x,y+1,s);//不放皇后 直接遍历下一个格子
    
    if(!row[x] && !col[y] && !dg[x+y] && !udg[y-x+n])//可以放
    {
        q[x][y]='Q';
        row[x]=col[y]=dg[x+y]=udg[y-x+n]=true;
        dfs(x,y+1,s+1);//遍历下一个格子,皇后个数+1
        q[x][y]='.';//恢复现场
        row[x]=col[y]=dg[x+y]=udg[y-x+n]=false;
    }
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            q[i][j]='.';//全部初始化为.
    
    dfs(1,1,0);//从左上第一个点开始dfs,皇后个数为0
    return 0;
    
}
//下标0开始
#include<iostream>
using namespace std;
const int N=20;
char q[N][N];
int n;
bool row[N],col[N],dg[N],udg[N];

void dfs(int x,int y,int s)
{
    if(y==n) y=0,x++;
    if(x==n) 
    {
    	if(s==n)
    	{
    		for(int i=0;i<n;i++) puts(q[i]);
       	    puts("");
		}
        
        return;
    }
    
    dfs(x,y+1,s);
    
    if(!row[x] && !col[y] && !dg[x+y] && !udg[y-x+n])
    {
        q[x][y]='Q';
        row[x]=col[y]=dg[x+y]=udg[y-x+n]=true;
        dfs(x,y+1,s+1);
        q[x][y]='.';
        row[x]=col[y]=dg[x+y]=udg[y-x+n]=false;
    }
}

int main()
{
    cin>>n;
    
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            q[i][j]='.';
            
    dfs(0,0,0);
    
    return 0;
    
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值