题目传送门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;
}