HDU 2553 N皇后问题

本文详细介绍了使用回溯法解决N皇后问题的方法,并提供了迭代和递归两种实现方案。通过调整约束函数,还展示了如何利用该算法求解N个数的全排列及特定数量的排列。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

N皇后问题

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 5976    Accepted Submission(s): 2728


Problem Description
在N*N的方格棋盘放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成45角的斜线上。
你的任务是,对于给定的N,求出有多少种合法的放置方法。

 

Input
共有若干行,每行一个正整数N≤10,表示棋盘和皇后的数量;如果N=0,表示结束。
 

Output
共有若干行,每行一个正整数,表示对应输入行的皇后的不同放置数量。
 

Sample Input
  
1 8 5 0
 

Sample Output
 
  
1 92 10
 

Author
cgf
 

Source
 

Recommend
lcy
题目意思是:求出所有满足八皇后(属于排列求解)的解。用回溯法穷举出所有发生的可能,通过约束函数对其剪枝,求出可行解。
贴张4皇后解的图形分析
采用迭代和递归式两方式求出解(其约束函数相同):
迭代式(非递归)
#include <iostream>
#include <cmath>
#include <cstring>
using namespace std;
#define N 11
int x[N];
int ans[N];
int s;
int place(int k)
{
    int i;
    for(i=1;i<k;i++)
    {
           if(x[i]==x[k] || abs(i-k)==abs(x[i]-x[k]))
                         return 0;
    }
    return 1;
}

void queen(int n)
   {
       for (int i=1; i<=n; i++)    //初始化
          x[i]=0;
      int k=1;
       while (k>=1)
       {
            x[k]=x[k]+1;     //在下一列放置第k个皇后
            while (x[k]<=n && !place(k)) 
            x[k]=x[k]+1;     //搜索下一列
            if (x[k]<=n && k==n) {   //得到一个解,输出
              s++;
            }
            else if (x[k]<=n && k<n)
                        k=k+1;      //放置下一个皇后
                  else {      
                      x[k]=0;     //重置x[k],回溯
                      k=k-1;
                  }
          }
     }
   


int main()
{
    int n;
    memset(ans,0,sizeof(ans));
    while(scanf("%d",&n),n)
    {
        if(!ans[n])
        {
             s=0;   
             queen(n);   
             ans[n]=s;
        }                          
        cout<<ans[n]<<endl;
    }
    return 0;
}

递归式
#include <iostream>
#include <cmath>
#include <cstring>
using namespace std;
#define N 11
int x[N];
int ans[N];
int s;
int place(int k)
{
    int i;
    for(i=1;i<k;i++)
    {
           if(x[i]==x[k] || abs(i-k)==abs(x[i]-x[k]))
                         return 0;
    }
    return 1;
}

void queen(int n,int t)
{
     int i;
     if (t>n)
     {
             s++;
             return ;
     }
     for(i=1;i<=n;i++)
     {
            x[t]=i;
            if(place(t))
                        queen(n,t+1);
            
     }
     
 }

int main()
{
    int n;
    memset(ans,0,sizeof(ans));
    while(scanf("%d",&n),n)
    {
        if(!ans[n])
        {
             memset(x,0,sizeof(x));
             s=0;   
             queen(n,1);   
             ans[n]=s;
        }                          
        cout<<ans[n]<<endl;
    }
    return 0;
}

通过对八皇后的理解。。更改代码即可求出N个数的全排列
#include <stdio.h>
#include <math.h>
#include <string.h>
#define N 11
int x[N];
int ans[N];
int s;
int place(int k)
{
    int i;
    for(i=1;i<k;i++)
    {
           if(x[i]==x[k])//这里与八皇后的约束条件少了一个,只要不在同一行,同一列即可
                         return 0;
    }
    return 1;
}

void queen(int n,int t)
{
     int i;
     if (t>n)
     {
             s++;//这里时候已经找到了一个可行解,输出数组X的元素即可,s所纪录的是所有的排列数
			 for(i=1;i<t;i++)
		    	printf("%d ",x[i]);
			 printf("\n");
             return ;
     }
     for(i=1;i<=n;i++)
     {
            x[t]=i;//因为每次选取的时候,数组X都把i的值放到其数组对应t下标中,虽然存取了所有可行与不可行的解,但是约束函数给予的只有可行解
           if(place(t))
		   { 
			   queen(n,t+1);
		   }
		  
     } 
 }

int main()
{
    int n;
    memset(ans,0,sizeof(ans));
    while(scanf("%d",&n),n)
    {
        if(!ans[n])
        {
             memset(x,0,sizeof(x));
             s=0;   
             queen(n,1);
			 printf("\n");
        }                          
      
    }
    return 0;
}

求出了N的全排列 即可以求出N个数里面的M排列:
#include <stdio.h>
#include <math.h>
#include <string.h>
#define N 11
int x[N];
int ans[N];
int s;
int place(int k)
{
    int i;
    for(i=1;i<k;i++)
    {
           if(x[i]==x[k])//这里与八皇后的约束条件少了一个,只要不在同一行,同一列即可
                         return 0;
    }
    return 1;
}

void queen(int n,int t)
{
     int i;
     if (t>n)///////改变这里的结束范围即可,比如N个数里面求3个数的排列,只要把n改为3即可
     {
             s++;//这里时候已经找到了一个可行解,输出数组X的元素即可,X所纪录的是所有的排列数
			 for(i=1;i<t;i++)
		    	printf("%d ",x[i]);
			 printf("\n");
             return ;
     }
     for(i=1;i<=n;i++)
     {
            x[t]=i;//因为每次选取的时候,数组X都把i的值放到其数组对应t下标中,虽然存取了所有可行与不可行的解,但是约束函数给予的只有可行解
           if(place(t))
		   { 
			   queen(n,t+1);
		   }
		  
     } 
 }

int main()
{
    int n;
    memset(ans,0,sizeof(ans));
    while(scanf("%d",&n),n)
    {
        if(!ans[n])
        {
             memset(x,0,sizeof(x));
             s=0;   
             queen(n,1);
			 printf("\n");
        }                          
      
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值