题目大意:n*n的地图,'.'表示空地,'X'表示墙,现在往地图上放置炮塔,要求两两炮塔不能同行同列(除非之间有墙),给定一种地图,问这个地图最多可以放置多少个炮塔?
Sample input:
4 .X.. .... XX.. .... 2 XX .X 3 .X. X.X .X. 3 ... .XX .XX 4 .... .... .... .... 0
Sample output:
5 1 5 2 4
/***********************************************************************
这是我一开始自己写的,WA,后来发现原因了:
3
...
.XX
.XX
此时答案错误,因为这种方法不能得出最优的布局,它只会在第一个放入碉堡!!
************************************************************************/
#include<stdio.h>
int main()
{
int n=0;
scanf("%d",&n);
while(n!=0){
bool flagR[n]; //行
bool flagC[n]; //列
char map[n+1][n+1];
int blockNum=0;
for(int i=1;i<n+1;i++){ //初始化
flagR[i]=false;
flagC[i]=false;
}
for(int i=0;i<n+1;i++)
map[i][0]='X';
for(int j=0;j<n+1;j++)
map[0][j]='X';
for(int i=1;i<n+1;i++){ //绘制地图
fflush(stdin);
for(int j=1;j<n+1;j++)
scanf("%c",&map[i][j]);
}
for(int i=1;i<n+1;i++){
for(int j=1;j<n+1;j++){
if(map[i][j]=='X')
continue;
if( (map[i-1][j]=='X' || flagC[j]==false) && (map[i][j-1]=='X' || flagR[i]==false) ){
blockNum++;
flagR[i]=true;
flagC[j]=true;
}
}
}
printf("%d\n",blockNum);
scanf("%d",&n);
}
return 0;
}
下面两个代码是参考网上的,都用了DFS,原理都差不多:
/************************************************************************************
由于题目的规模小,所以可采用DFS。
DFS:(深度优先搜索)对一个连通图进行遍历的算法。它的思想是从一个顶点V0开始,沿着一条路一直走到底,
如果发现不能到达目标解,那就返回到上一个节点,然后从另一条路开始走到底。
***********************************************************************************/
#include<iostream>
using namespace std;
char map[4][4];
int maxNum,n=0;
bool canPut(int row,int col) {
int i;
for(i=row-1; i>=0; i--) {
if(map[i][col]=='o')
return false;
if(map[i][col]=='X')
break;
}
for(i=col-1; i>=0; i--) {
if(map[row][i]=='o')
return false;
if(map[row][i]=='X')
break;
}
return true;
}
void DFS(int k,int curNum) { //curNum:在当前布置下,所获得的能够合法布置的碉堡最大值
int x,y;
if(k==n*n) { //整个地图判断结束
if(curNum>maxNum) {
maxNum=curNum;
return;
}
} else {
x=k/n; //行号
y=k%n; //列号
if(map[x][y]=='.' && canPut(x,y)==true){ //该单元格为空,且可以放置碉堡
map[x][y]='o'; //放置堡垒
DFS(k+1,curNum+1); //递归进入到下一个单元格
map[x][y]='.'; //回溯,恢复该单元格,为下一个放置做准备
}
DFS(k+1,curNum); //当前单元格不能放置或回溯回来的时候用到
}
}
int main()
{
int i,j;
while(cin>>n && n){
maxNum=0; //初始化
for(i=0;i<n;i++) //输入地图
for(j=0;j<n;j++)
cin>>map[i][j]; //cin忽略空白和回车,若这里用scanf输入,则会把回车键算入,要用fflush(stdin)消除
DFS(0,0); //从地图的左上角开始进行深度搜索
cout<<maxNum<<endl;
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
int visit[10][10],mmax,n,cou;
//visit里,0是啥都没放,1是放了碉堡,2是放了防火墙
//cou计数放的个数,mmax记录最大cou的最大值,即题目要求值
int find(int x,int y) // 判断是否可以放置
{
for(int i=y; i>=1; i--) //四个循环,从点(X,Y)上下左右判断,如果有碉堡,返回0,如果有墙,继续下个循环。
{
if( visit[x][i] == 1 )
return 0;
if( visit[x][i] == 2 )
break;
}
for(int i=y; i<=n; i++)
{
if( visit[x][i] == 1 )
return 0;
if( visit[x][i] == 2 )
break;
}
for(int i=x; i>=1; i--)
{
if( visit[i][y] == 1 )
return 0;
if( visit[i][y] == 2 )
break;
}
for(int i=x; i<=n; i++)
{
if( visit[i][y] == 1 )
return 0;
if( visit[i][y] == 2 )
break;
}
return 1;
}
void DFS()
{
if( cou > mmax )
mmax = cou;
for(int k=1; k<=n; k++)
for(int h=1; h<=n; h++)
if( !visit[k][h] && find(k,h) ) //该位置为空,且可以放置碉堡
{
visit[k][h] = 1;
cou++;
DFS();
visit[k][h] = 0;
cou--;
}
}
int main(void)
{
char str[10];
while( cin >> n && n)
{
mmax = 0; cou = 0;
for(int i=1; i<=n; i++)
{
cin >> str;
for(int k=0; k<n; k++)
visit[i][k+1] = (str[k] == 'X' ? 2 : 0 );
}
DFS();
cout << mmax << endl;
}
return 0;
}
有点不好意思的是,借鉴代码的网址没及时保存……