子曰:“吾尝终日不食、
终夜不寝以思,无益,不如学也。”
孔子说:"我曾经常终日不吃饭,整夜不睡觉来思考,没有长进,不如学习."
本文讲述了棋盘上的问题.
首先,我们要亮相的是大家都知道的问题,著名的八皇后问题!
高斯大佬好像求错了,他认为有76种.但是他是手算的,人无完人,金无赤足.
皇后的攻击范围
在这个问题上,我们使用状态压缩集合的技巧。
虽然我们是通过搜索的形式,但是我们赋予其递推的意义,
运用数学的表述形式,描述了程序.
#include<bits/stdc++.h>
using namespace std;
int ans;
int n;
void dfs(int now,int col,int dia,int rev_dia)
{
if(now==n)
{
ans++;
return ;
}
for(int i=0;i<n;i++)
{
if(col>>i&1)
{
continue;
}
int now_dia=now-i+n-1;
if(dia>>now_dia&1)continue;
int now_rev_dia=i+now;
if(rev_dia>>now_rev_dia&1)continue;
dfs(now+1,col|(1<<i),dia|(1<<now_dia),rev_dia|(1<<now_rev_dia));
}
}
signed main()
{
n=8;
dfs(0,0,0,0);
cout<<ans;
}
那么怎没知道pre和now是相容的?
我们提前将满足一行的国王摆法,安排好。
同时,将每一个now的前面可以转移的状态枚举出来。
这是一个双马问题,在一个n×n的棋盘上,有多少种放两个马的方法。
但是马的放置是没有顺序的,通过乘法原理,消除顺序。
#include<bits/stdc++.h>
using namespace std;
#define int long long
int solve(int n)
{
int ans=0;
if(n==1)return 0;
if(n==2)return 6;
if(n==3)return 28;
if(n==4)return 96;
if(n==5)return 252;
if(n==6)return 550;
ans=(n-4)*(n-4)*(n*n-9);
ans+=(n-4)*4*(n*n-6-1);
ans+=4*(n*n-5);
ans+=8*(n*n-4);
ans+=4*(n-4)*(n*n-5);
ans+=4*(n*n-3);
return ans/2;
}
signed main(){
int n;
cin>>n;
for(int i=1;i<=n;i++)
cout<<solve(i)<<"\n";
}
接下来的就是跳马问题,
有没有可能,这个马将格子跳一次,并且只有一次?
这道题是典型的哈密顿回路问题。
我们还是使用搜索的方式。
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m;
const int N=1010;
int dx[]={-1,-1,1,1,2,2,-2,-2};
int dy[]={2,-2,2,-2,1,-1,1,-1};
int vis[N][N];
bool check(int x,int y)
{
return x>=0&&x<n&&y<m&&y>=0;
}
void dfs(int x,int y,int cnt)
{
if(cnt==n*m)
{
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
cout<<vis[i][j]<<" ";
cout<<"\n";
}
exit(0);
}
for(int i=0;i<8;i++)
{
int xx=dx[i]+x;
int yy=dy[i]+y;
if(!check(xx,yy))
{
continue;
}
if(vis[xx][yy])continue;
vis[xx][yy]=cnt;
dfs(xx,yy,cnt+1);
vis[xx][yy]=0;
}
}
signed main()
{
n=4;
m=8;
dfs(0,0,1);
cout<<"NO";
}
当然也可以是状态压缩.
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m;
const int N=1010;
int dx[]={-1,-1,1,1,2,2,-2,-2};
int dy[]={2,-2,2,-2,1,-1,1,-1};
map<int,int>f[20][20];
bool check(int x,int y)
{
return x>=0&&x<n&&y>=0&&y<m;
}
void print(int x)
{
for(int i=32;i>=0;i--)
{
if(x>>i&1)
cout<<1;
else cout<<0;
}
cout<<"\n";
}
bool dfs(int x,int y,int st)
{
// cout<<x<<" "<<y<<" ";
// cout<<st<<"\n";
//print(st);
if(st==(1ll<<(n*m))-1)
{
return true;
}
if(f[x][y].count(st))
{
return f[x][y][st];
}
bool res=0;
for(int i=0;i<8;i++)
{
int xx=x+dx[i];
int yy=y+dy[i];
if(!check(xx,yy))continue;
if((st>>(xx*m+yy))&1)continue;
// if((st|(1ll<<(xx*m+yy)))<0)//1ll<< 1ll<< int 右移动太小,因该1ll<<
// {
// cout<<"\n";
// print(1ll<<(xx*m+yy));
// cout<<(1ll<<(xx*m+yy))<<"\n";
// cout<<x<<" "<<y<<" ";
// print(st);
// cout<<" "<<xx<<" "<<yy<<"\n";
// exit(0);
// }
res|=dfs(xx,yy,st|(1ll<<(xx*m+yy)));
if(res)break;
}
return f[x][y][st]=res;
}
signed main()
{
n=4,m=3;
cout<<dfs(0,0,1);
}
只是可能加速效果不是很出色.
并且状态的空间增量特别大.
8×8跳马的一种方案