题意:给出一个象棋矩阵,在部分点上有棋子,问其他空点上最多能够放置多少个炮并且使得所有炮两两之间不能相互攻击(可以相互攻击指的就是炮与炮之间有且只有一个棋子)。
解法:由于矩阵最大5*5,所以2^25有点勉强,,但是中间过程的剪枝真的很有效,而且可以保证只要深搜到最后一个格子就一定是合法的排布。深搜是从左上到右下,这个剪枝就是每放一个炮时,都在其所在行与列检查一下是否有可以攻击的炮,检查的方法就是代码里的fx,fy函数,只有在此炮合法的情况下才继续往下搜,否则剪掉,最后搜到底的时候一定都是合法的。
代码:
#include <iostream>
#include <stdio.h>
#include <cstring>
using namespace std;
int num[8][8];
int N,M,Q;
int ans;
bool fx(int i,int j,int di,int t)
{
i+=di;
if(i<0||i>=N)return false;
if(t==1&&num[i][j]==2)
return true;
if(num[i][j]==2||num[i][j]==3)
t++;
if(t==3)
return false;
return fx(i,j,di,t);
}
bool fy(int i,int j,int di,int t)
{
j+=di;
if(j<0||j>=M)return false;
if(t==1&&num[i][j]==2)
return true;
if(num[i][j]==2||num[i][j]==3)
t++;
if(t==3)
return false;
return fy(i,j,di,t);
}
bool OK()
{
for(int i=0;i<N;i++)
{
for(int j=0;j<M;j++)
{
if(num[i][j]==2)
{
if(fx(i,j,-1,0))
return false;
if(fx(i,j,1,0))
return false;
if(fy(i,j,-1,0))
return false;
if(fy(i,j,1,0))
return false;
}
}
}
return true;
}
void dfs(int k)
{
if(k==N*M)
{
int tool=0;
for(int i=0;i<N;i++)
for(int j=0;j<M;j++)
if(num[i][j]==2)
tool++;
ans=max(ans,tool);
return;
}
int i=k/M,j=k%M;
if(num[i][j]==0)
{
num[i][j]=1;
dfs(k+1);
num[i][j]=2;
if(!fx(i,j,-1,0)&&!fy(i,j,-1,0))
dfs(k+1);
num[i][j]=0;
}
else
dfs(k+1);
}
int main()
{
while(scanf("%d%d%d",&N,&M,&Q)==3)
{
memset(num,0,sizeof num);
ans=0;
int x,y;
while(Q--)
scanf("%d%d",&x,&y),num[x][y]=3;
dfs(0);
cout<<ans<<endl;
}
return 0;
}