ZOJ-1002

题目大意: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;
}

有点不好意思的是,借鉴代码的网址没及时保存……

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值