hdu2553N皇后问题

N皇后问题

打表 

 #include<iostream>
 using namespace std;
 int a[11]={0,1,0,0,2,10,4,40,92,352,724};
 int main()
 {
     int n;
     while(scanf("%d",&n)>0&&n)
     {
         printf("%d\n",a[n]);
     }
     return 0;
 }


/************************************************************
 * Author        : rudolf
 * Last modified : 2013-04-23 15:27
 * Filename      : caogao.cpp
 * Description   :
 * *********************************************************/
#include <stdio.h>
#include <iostream>
#include<string.h>
using namespace std;
int map[20],a[20],hang[20],n,cnt;
void DFS(int num)
{
	int i,j,flag;
	if(num==n+1)//到n也成立了才会搜索n+1
	{
		cnt++;return;
	}
	for(i=1;i<=n;i++)
		if(!hang[i])//不在同一行
		{
			flag=1;map[num]=i;//第num列第i行放第num个皇后
			for(j=1;j<num;j++)
				if((map[num]-num==map[j]-j)||(map[num]+num==map[j]+j))//判断是否在对角线上
				{	
					flag=0;
					break;
				}
				if(flag)
				{
					hang[i]=1;
					DFS(num+1);//递归调用
					hang[i]=0;//回溯
				}
		}
}
int main()
{
	int i,m;
	for(i=1;i<11;i++)//打表列出N个皇后对应几种方法
	{
		memset(map,0,sizeof(map));
		memset(hang,0,sizeof(hang));
		n=i;cnt=0;
		DFS(1);
		a[i]=cnt;
	}
	while(cin>>m&&m!=0)
		cout<<a[m]<<endl;
	return 0;
}


/**
n皇后问题,由于N 是小于等于10的正整数,
所以可以使用打表的方法把前十中情况全
部找出来存起来然后每次输入时不用重新
的计算了。
*/
#include <stdio.h>

#define NUMS 10
/*输入的数字1---10*/
int N;
/*棋盘*/
int chessboard[11][11];
/* 用来记录拜访数目 */
int cal;

/*
检查皇后放置此行此列是否可以,可以返回1,不可以返回0
此递归是一行一行找的,K是棋盘的长度
*/
int dfs_check(int row,int column,int k)
{
    /* 说明已经到了棋盘的界外,前边都符合了 */
    if(row>k)
    {
        cal++;
        return 1;
    }
    /* 正上方是否有皇后*/
    for(int i = 1; i < row; i++)
        /* 如果有皇后则返回不能放置这里返回0*/
    if(chessboard[i][column] == 1)
    return 0;

    /* 左右上方45度角检查是否可以*/
    /* 左上方*/
    for(int i=row-1,j=column-1;i>0&&j>0;i--,j--)
    if(chessboard[i][j] == 1)
    return 0;
    /* 右上方*/
    for(int i=row-1,j=column+1;i>0&&j<=k;i--,j++)
    if(chessboard[i][j] == 1)
    return 0;
    /*标记这个位置成功了*/
    chessboard[row][column] = 1;

    /*进行下一行搜索*/
    for(int i=1;i<=k;i++)
    if(dfs_check(row+1,i,k)==1)
    break;

    chessboard[row][column] = 0;
    return 0;
}


int main()
{
    int i,j,k;
    int count[11];
    /*打表*/
    for(k=1;k<=NUMS;k++)
    {
        count[k] = 0;
        cal = 0;
        /*首先将棋盘初始化全部置为0*/
        for(i=0;i<=NUMS;i++)
        for(j=0;j<=NUMS;j++)
        chessboard[i][j]=0;
        for(i=1;i<=k;i++)
        dfs_check(1,i,k);
        count[k] = cal;
    }

    while(scanf("%d",&N)!=EOF&&N!=0)
    printf("%d\n",count[N]);
    return 0;
}



回溯法(转)能力有限,理解不了他的代码http://blog.csdn.net/alongela/article/details/6755770

用回溯法就可以解决,设皇后的编号依次为1,2,……,n,则可以认为第i个皇后必须摆放在第i行,然后枚举第一个皇后的位置进行回溯,若某一次发现某个皇后无法找到摆放位置则直接返回,如果所有皇后都可以找到摆放位置,则说明存在一种摆法满足要求,统计有多少种摆法即可。


此题n<=10,测试数据中会有大量重复数据,因此要保存答案,遇到曾经计算过的n直接输出即可,否则可能会超时。

#include<iostream>
using namespace std;
int n;
int x[100];
int ans[11];
bool Place(int k)
{
	int i = 1;
	while (i<k)
	{
		if (x[i]==x[k] || abs(x[i]-x[k])==abs(i-k))	return false;
		i++;
	}
	return true;
}
int main()
{
	int k, cnt;
	memset(ans, 0, sizeof(ans));
	while (scanf("%d", &n)!=EOF && n!=0)
	{
		if (ans[n]>0) 
		{
			printf("%d\n", ans[n]);
			continue;
		}
		x[1] = 0;
		k = 1, cnt = 0;
		while (k>0)
		{
			x[k]++;
			while (x[k]<=n && !Place(k))
			{
				x[k]++;
			}
			if (x[k]<=n)
			{
				if (k==n)
				{
					cnt++;
				}
				else 
				{
					k++;
					x[k] = 0;
				}
			}
			else k--;
		}
		ans[n] = cnt;
		printf("%d\n", cnt);
	}
	return 0;
}

dfs

#include<iostream>
 #include<math.h>
 using namespace std;
 int s[12][12],n,count;
 int panduan(int h,int l)
 {
     for(int i=0;i<n;i++)           //判断列
     {
         if(s[i][l]==0||i==h)
             continue;
         else
             return 0;
     }
     for(i=0;i<n;i++)            //判断行
     {
         if(s[h][i]==0||i==l)
             continue;
         else
             return 0;
     }
     for(i=0;i<n;i++)          //判断成45度的线
     {
         for(int j=0;j<n;j++)
         {
             if(s[i][j]==0||(i==h&&j==l))
                 continue;
             else
             {
                 if(abs(h-i)==abs(l-j))          //只要y=kx+b中abs(k)==1,说明成了45度的线
                     return 0;
             }
         }
     }
     return 1;
 }
 void dfs(int num,int f)
 {
     int i,j;
     if(num==n*n)
     {
         if(f==0)
             count++;
         return;
     }
     if(num>n*n)return;
     i=num/n;
     j=num%n;
     if(s[i][j]==0&&panduan(i,j))
     {
         s[i][j]=1;
         dfs(num+1,f-1);
         s[i][j]=0;
     }
     dfs(num+1,f);
 }
 int main()
 {
     while(scanf("%d",&n)>0&&n)
     {
         memset(s,0,sizeof(s));
         count=0;
         dfs(0,n);
         //printf("\n\n");
         printf("%d\n",count);
     }
     return 0;
 }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值