城堡 The Castle(uscao)

题目传送门sxazr
本体真的是因为细节问题花费了我将近两个小时的光阴啊
认真,仔细!
找连通块,每找完一个连通块把连通块内的每个方格标记上该连通块的序号,
( 在后面拆墙时判断是否在一个连通块里)记录最大的连通块;
枚举每个方格,拆墙(这里只枚举上面的墙和左面的墙就可以),记录最好的拆墙位置;
注意多解时选择输出那个;
输出有多少个连通块;
代码

#include <iostream>
#include <cstdio>
using namespace std;
const int N=52;
int m,n,f[N][N],q[N][N],r1,r2,v[10001],num;//v表示连通块的大小
int st1[2501],st2[2501],top;
int max1,max2,h,l,g;
bool wal[N][N][N][N];
int o[4][2]={{-1,0},{0,1},{1,0},{0,-1}};
void ad(int x,int y,int k)    //建墙
{
	if(k>=8){
		wal[x][y][x+1][y]=1;
		k-=8;
	}
	if(k>=4){
		wal[x][y][x][y+1]=1;
		k-=4;
	}
	if(k>=2){
		wal[x][y][x-1][y]=1;
		k-=2;
	}
	if(k>=1) wal[x][y][x][y-1]=1;
	return;
}
void zr(int x,int y)//找连通块
{
	q[x][y]=1;
	st1[++top]=x;st2[top]=y;
	for(int i=0;i<4;i++){
		int a=x+o[i][0],b=y+o[i][1];
		if(a<1||b<1||a>n||b>m) continue;
		if(wal[x][y][a][b]||q[a][b]) continue;
		zr(a,b);
	}
	if(x==r1&&y==r2){
		num++;v[num]=top;max1=max(max1,top);
		while(top) f[st1[top]][st2[top]]=num,top--; 连通块内的做标记
	}
	return;
}
int main()
{
	cin>>m>>n;
	for(int i=1;i<=n;i++)
	  for(int j=1;j<=m;j++){
	 	int x;
	 	scanf("%d",&x);
	 	ad(i,j,x);
	  }
	for(int i=1;i<=n;i++)
	  for(int j=1;j<=m;j++){
	  	if(f[i][j]||q[i][j]) continue;
	  	top=0;
	  	r1=i;r2=j;
	  	zr(i,j);
	  }
	for(int i=1;i<=n;i++)
	  for(int j=1;j<=m;j++)
	  	for(int k=0;k<2;k++){
	  		int x=i+o[k][0],y=j+o[k][1];
	  		if(x<1||y<1||x>n||y>m) continue;
	  		if(!wal[i][j][x][y]||f[i][j]==f[x][y]) continue;
	  		if(v[f[i][j]]+v[f[x][y]]>max2){
	  			max2=v[f[i][j]]+v[f[x][y]];
	  			h=i;l=j;g=k;
			  }
			else if(v[f[i][j]]+v[f[x][y]]==max2){
				if(j>l) continue;
				if(i==h&&j==l) continue; //多解
				h=i;l=j;g=k;
			}
		}
	printf("%d\n%d\n%d\n%d %d ",num,max1,max2,h,l);
	if(g==0) cout<<"N";
	else cout<<"E";
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值