世界名画陈列馆由 mx n 个陈列室组成 为防止名画被盗,需要在陈列室中设置警卫机器人哨位 每个警卫机器人除了监视它所在的陈列室外,还可监视与它所在陈列室相邻的上、下、 左、右 4 个陈列室 设计一个算法,安排警卫机器人哨位,使得名画陈列馆中每一个陈列室都在警卫机器人 的监视之下,且所用的警卫机器人最少:
#include <iostream>
#include <string.h>
#include <cmath>
#include <windows.h>
#include <stdlib.h>
using namespace std;
int n,m,now;
bool map[25][25],ans[25][25];
inline bool covered(int x,int y)//判断棋子是否被填充或者已经越界
{
if (map[x][y]==true || (x-1>=1 && map[x-1][y]==true) || (x+1<=n && map[x+1][y]==true) || (y-1>=1 && map[x][y-1]==true) || (y+1<=m && map[x][y+1]==true))
return(true);
return(false);
}
//x,y为坐标,sum为放的格子总数,pre代表上一次放棋子的时候假设空白格子为(x,y),那么pre1==true的时候
//棋子中心放在了(x,y)上,pre2为true的时候放在了(x,y+1)上,pre3为true的时候放在了(x+1,y)上
void find(int x,int y,int sum,bool pre1,bool pre2,bool pre3)
{
//表示如果剩下的课放置的次数都填充了最大的5个还小于剩下的棋盘格子总数的时候,肯定不可以;
if (sum>now || (now-sum)*5<(n-x-1)*m) return;
//已经到了最后一个格子
if (x==n && y==m)
{
if (covered(x,y)==false)
sum++;
//如果比上界要小,就保存结果并缩小上界
if (now-sum>=0)
{
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
ans[i][j]=map[i][j];
if (covered(x,y)==false) ans[x][y]=true;
now=sum-1;
}
return;
}
//如果要换行或者已经被填充为黑色的时候
if (y>m || covered(x,y)==true)
{
//换行的时候把pre都置位f,不换行就保存pre继续dfs;
if (y+1<=m) find(x,y+1,sum,pre1,pre2,pre3);
else find(x+1,1,sum,false,false,false);
return;
}
//三个预判格子都为白色
if (y+1<=m && x+1<=n && covered(x+1,y)==false && covered(x,y+1)==false)
{
//棋子中心放在(x,y)
if (pre1==false)
{
map[x][y]=true;
find(x,y+1,sum+1,true,false,false);
map[x][y]=false;
}
if (sum>now || (now-sum)*5<(n-x-1)*m) return;
//棋子中心放在(x+1,y)
if (pre2==false)
{
map[x+1][y]=true;
find(x,y+1,sum+1,false,true,false);
map[x+1][y]=false;
}
if (sum>now || (now-sum)*5<(n-x-1)*m) return;
//棋子中心放在(x,y+1)
if (pre3==false)
{
map[x][y+1]=true;
find(x,y+1,sum+1,false,false,true);
map[x][y+1]=false;
}
}
//(x,y+1)为黑的时候要中心放在(x+1,y)为最优的
else if (y+1<=m && x+1<=n && covered(x+1,y)==false && covered(x,y+1)==true)
{
map[x+1][y]=true;
find(x,y+1,sum+1,false,true,false);
map[x+1][y]=false;
}
//(x+1,y)为黑的时候要中心放在(x,y+1)为最优的
else if (y+1<=m && x+1<=n && covered(x+1,y)==true && covered(x,y+1)==false)
{
map[x][y+1]=true;
find(x,y+1,sum+1,false,false,true);
map[x][y+1]=false;
}
//特判(n,m-1)
else if (y+1<=m && x+1>n)
{
map[x][y+1]=true;
find(x,y+1,sum+1,true,true,false);
map[x][y+1]=false;
}
//特判(n-1,m)
else if (y+1>m)
{
map[x+1][y]=true;
find(x,y+1,sum+1,false,false,false);
map[x+1][y]=false;
}
}
void display()//画出棋盘
{
int i,j,k;
cout<<"┏";
for (i=1;i<m;i++) cout<<"━┯";
cout<<"━┓"<<endl;
for (i=0;i<n;i++)
{
if (i)
{
cout<<"┠";
for( k=1;k<m;k++) cout<<"─┼";
cout<<"─┨"<<endl;
}
cout<<"┃";
for(j=0;j<m;j++)
{
if(j) cout<<"│";
if(ans[i+1][j+1]) cout<<"●";
else cout<<" ";
}
cout<<"┃"<<endl;
}
cout<<"┗";
for(i=1;i<m;i++)
cout<<"━┷";
cout<<"━┛"<<endl;
}
int main()
{
cin>>n>>m;
int s=GetTickCount();
now=ceil((n*m)/3.0);
find(1,1,0,false,false,false);
now++;
cout<<now<<endl;
display();
int e=GetTickCount();
cout<<(e-s)/1000.0<<endl;//计时
return(0);
}