HDOJ-1031 N皇后问题

题目

N*N的方格棋盘放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成45角的斜线上。

输入给定的NN≤10),输出有多少种合法的放置方法。

思路

N*N棋盘中摆N个皇后,意味着每行有一个皇后,每列有一个皇后,每条主对角线有一个皇后,每条副对角线有一个皇后;换言之,每个皇后控制着一行、一列。一条主对角线、一条副对角线。因此,以每行对应一次循环,用a,b,c三个数组存储各主对角线、副对角线、列的占用情况。点(x,y)位于第x行,第y列,第y-x+n条主对角线(1-n<=y-x<=n-1,处理使数组从1开始),第x+y条副对角线(2<=x+y<=2n)

代码

#include<iostream>
#include<cstring>
using namespace std;
int n,so;
bool a[25],b[15],c[25];//a代表主对角线,b代表列,c代表副对角线
void dfs(int i)
{
	if(i>n) {so++;return;}
	for(int j=1;j<=n;j++)//每列
	{
		if(a[j-i+n]||b[j]||c[i+j]) continue;//不可用,则跳过
		a[j-i+n]=true;b[j]=true;c[i+j]=true;//标记控制区域
		dfs(i+1);//查找下一行可用点
		a[j-i+n]=false;b[j]=false;c[i+j]=false;//取消标记
	}
}
int main()
{
	int ans[15]={0};
	for(n=1;n<=10;n++)
	{
		memset(a,false,sizeof(a));
		memset(b,false,sizeof(b));
		memset(c,false,sizeof(c));	
		so=0;dfs(1);ans[n]=so;
	}
	while(cin>>n&&n)
		cout<<ans[n]<<endl;
	return 0;
}

HDOJ-1426 Sudoku Killer

题目

输入一批不完整的数独地图(未知数值用’?’表示),输出它们的解。(对于每组测试数据保证它有且只有一个解)

思路

仔细分析,发现与上一题有类似之处:小格中的每一个数字x,都可以看做是所在行、列、九宫格的数字x的控制数字——这个数字控制着所在行、列、九宫格,在其控制区域内不能出现另一个x。用结构体存储空格的位置,i0~8)代表小格行标,j0~8)代表小格列标,则i/3代表九宫格行标,j/3代表九宫格列标。以每个空格对应一层递归,用a,b,c三个数组存储各行、列、九宫格的可用性,数组最后一维代表9个可能的数字,其他维度代表序号。

由题意,每个空格的值不全为9。当从最后一个空格(已填写)出发进行下一层递归时,触发条件空格溢出,记录填写完成,函数返回到倒数第二个空格的下一次循环。填写完成条件满足,循环变量的上一个值填写到真正的数独空格中,函数再返回到倒数第三个空格……对于值为9的情况,在循环之外另行处理。

用两层循环读入数独地图存到字符数组中,读入的字符若是数字,标记控制区域;若是空格,记录其位置坐标。

代码

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
char map[9][9];
struct space
	{int i;int j;}s[81];
bool a[9][12],b[9][12],c[3][3][12];//a代表行,b代表列,c代表九宫格
int sn,snm;//sn=Space Number空格编号,snm=空格编号最大值
int done;//done为1代表所有空格填写完成
void dfs(int sn)
{
	if(sn>snm) {done=1;return;}
	int v;
	for(v=1;v<=9;v++)//每个可能值
	{
		if(done==1) {map[s[sn].i][s[sn].j]='0'+v-1;break;}
		if(a[s[sn].i][v]||b[s[sn].j][v]||c[s[sn].i/3][s[sn].j/3][v]) continue;//不可用,则跳过
		a[s[sn].i][v]=true;b[s[sn].j][v]=true;c[s[sn].i/3][s[sn].j/3][v]=true;//标记控制区域
		dfs(sn+1);//填写下一个空格
		a[s[sn].i][v]=false;b[s[sn].j][v]=false;c[s[sn].i/3][s[sn].j/3][v]=false;//取消标记
	}
	if(v==10&&done==1) map[s[sn].i][s[sn].j]='0'+v-1;
}
int main()
{
	char ch;int f=1;
	do{
		int i,j;
		memset(a,false,sizeof(a));
		memset(b,false,sizeof(b));
		memset(c,false,sizeof(c));
		done=0;sn=0;
		for(i=0;i<9;i++)
		{
			for(j=0;j<9;j++)
			{
				cin>>ch;
				if(ch!='?') 
					{a[i][ch-'0']=true;b[j][ch-'0']=true;c[i/3][j/3][ch-'0']=true;}
				else {s[sn].i=i;s[sn].j=j;sn++;}
				map[i][j]=ch;
			}						
		}
		snm=sn-1;
		dfs(0);
		if(f==0) cout<<endl; else f=0;
		//第二组数据开始,输出前加一空行
		for(i=0;i<9;i++)
		{
			for(j=0;j<8;j++)
				cout<<map[i][j]<<" ";
			cout<<map[i][j]<<endl;			
		}	
	}while(scanf("%c",&ch)!=EOF);
	return 0;
}