hdu 1045 Fire Net

//题目大意:给一个最大不超过4x4的图,用X表示墙壁,问能在这张图上放多少个碉堡,每个碉堡可以向上,下,左,右四个方向发射子弹,但是墙可以挡住子弹,我们希望在放置最多碉堡的情况下,保证两两碉堡不会相互攻击到对方  
//最优策略:尽量在墙的四周放置碉堡。
//先将每个墙的位置记录下来,在墙的四周(上下左右放碉堡是最好的),按墙四周的所能安放碉堡的数目排序
//比如 . .X2    X1这个墙四周可以放4个碉堡,排在前面,下一个X2周围只能放两个排在后面
//         .X1.
//          . . .
//遍历每一个墙,在墙的周围放上碉堡,当然了,放置的时候还要判断该位置能否放碉堡。

//遍历完后,还要重新遍历整个图,防止没有墙壁以及 墙壁数量较少导致遗漏的情况。 

//因为墙壁隔着两者不会相互攻击,所以不是二分图的情况

#include<iostream>
#include<cstdio>
#include<memory>
#include<algorithm>
using namespace std;
struct Z
{
	int x;
	int y;
	int kong;
}z[17];//黑块 
int map[5][5];
int n;//4
int cmp(Z a,Z b)
{
	return a.kong>b.kong;
}
int testR(int r,int c)//判断r行是否允许安放碉堡 
{
	int flagL=1;//左边允许标志 
	int flagR=1;//右边允许标志 
	
	if(c==1){//如果在第一列,向右扫描 
		for(;c<=n;c++)
		{
			if(map[r][c]=='.')continue;
			if(map[r][c]=='X')break;
			if(map[r][c]=='N'){
				flagR=0;
				break;
			}//break;
		}
	}else if(c==n){//如果在最后一列,向左扫描 
		for(;c>=1;c--)
		{
			if(map[r][c]=='.')continue;
			if(map[r][c]=='X')break;
			if(map[r][c]=='N'){
				flagL=0;
				break;
			}//break;
		}
	}else{//如果在中间 
		int zuo=c-1;
		int you=c+1;
		for(;you<=n;you++)
		{
			if(map[r][you]=='.')continue;
			if(map[r][you]=='X')break;
			if(map[r][you]=='N'){
				flagR=0;
				break;
			}//break;
		} 
		for(;zuo>=1;zuo--)
		{
			if(map[r][zuo]=='.')continue;
			if(map[r][zuo]=='X')break;
			if(map[r][zuo]=='N'){
				flagL=0;
				break;
			}//break;
		}
	}
	return flagL && flagR;
}
int testC(int r,int c) //判断列c是否允许安放碉堡 
{
	int flagup=1;
	int flagdown=1;
	
	if(r==1){//扫描下方 
		for(;r<=n;r++)
		{
			if(map[r][c]=='.')continue;
			if(map[r][c]=='X')break;
			if(map[r][c]=='N'){
				flagdown=0;
				break;
			}//break;
		}
	}else if(r==n){//扫描上方 
		for(;r>=1;r--)
		{
			if(map[r][c]=='.')continue;
			if(map[r][c]=='X')break;
			if(map[r][c]=='N'){
				flagup=0;
				break;
			}//break;
		}
	}else{
		int shang=r-1;
		int xia=r+1;
		for(;xia<=n;xia++)
		{
			if(map[xia][c]=='.')continue;
			if(map[xia][c]=='X')break;
			if(map[xia][c]=='N'){
				flagdown=0;
				break;
			}//break;
		} 
		for(;shang>=1;shang--)
		{
			if(map[shang][c]=='.')continue;
			if(map[shang][c]=='X')break;
			if(map[shang][c]=='N'){
				flagup=0;
				break;
			}//break;
		}
	}
	return flagup && flagdown;
}
int main()
{
	scanf("%d",&n);
	while(n)
	{
		int i,j;
		int pos=0;
		for(i=1;i<=n;i++)
		{
			getchar();
			for(j=1;j<=n;j++)
			{
				scanf("%c",&map[i][j]);	
				if(map[i][j]=='X')
				{
					z[pos].x=i;
					z[pos].y=j;
					pos++;				
				}
			} 
		}
		int k=0;
		for(i=1;i<=n;i++) //统计每个墙周围能安放碉堡的个数 
		{
			for(j=1;j<=n;j++)
			{
				if(map[i][j]=='X')
				{
					int cnt=0;
					if(i>=2 && map[i-1][j]=='.'){
						cnt++;
					}
					if(i<=n-1 && map[i+1][j]=='.'){
						cnt++;
					}
					if(j<=n-1 && map[i][j+1]=='.'){
						cnt++;
					}
					if(j>=2 && map[i][j-1]=='.'){
						cnt++;
					}
					z[k].kong=cnt;
					k++;
				}
			}
		}
		sort(z,z+pos,cmp); //排序 
		int ans=0;
		for(i=0;i<pos;i++)//遍历每一个墙 
		{
			int x=z[i].x;
			int y=z[i].y;
			//上和下,列不变 
			int shang=x-1;
			if(shang>=1 && map[shang][y]=='.')//如果这个位置没有东西 
			{
				if(testR(shang,y))//如果这个行可以放 
				{
					if(testC(shang,y))
					{
						map[shang][y]='N';
						ans++;
					}
				}
			} 
			int xia=x+1;
			if(xia<=n &&map[xia][y]=='.')
			{
				if(testR(xia,y))//如果这个行可以放 
				{
					if(testC(xia,y))
					{
						map[xia][y]='N';
						ans++;
					}
				}
			}
			//左和右行不变 
			int zuo=y-1;
			int you=y+1;
			if(zuo>=1 && map[x][zuo]=='.')
			{
				if(testR(x,zuo))//如果这个行可以放 
				{
					if(testC(x,zuo))
					{
						map[x][zuo]='N';
						ans++;
					}
				}
			} 
			if(you<=n && map[x][you]=='.')
			{
				if(testR(x,you))//如果这个行可以放 
				{
					if(testC(x,you))
					{
						map[x][you]='N';
						ans++;
					}
				}
			} 
		}
		for(i=1;i<=n;i++) //补漏 
		{
			for(j=1;j<=n;j++)
			{
				if(map[i][j]=='.')
				{
					if(testR(i,j)&&testC(i,j))
					{
						map[i][j]='N';
						ans++;
					}
				}
			}
		}
//		for(i=1;i<=n;i++)
//		{
//			for(j=1;j<=n;j++)
//			{
//				printf("%c ",map[i][j]);
//			}
//			printf("\n");
//		}
		printf("%d\n",ans);	
		scanf("%d",&n);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值