洛谷P1457 城堡 The Castle /1104 USACO 2.1 城堡 (foodfill)
读题
当初看到这道题时,我的内心是奔溃的:
什么魔鬼输入?!
什么恶心要求?!
我 *(数据删除)
算了,还是好好做题吧。
输入处理
通过观察,我们可以知道每一个数都可以这样分解
假设某行有一个数
11
11
11,我们可以:把它拆成二进制:
11= 1 0 1 1
1/表示南面有墙
0/表示东面没有墙
1/表示北面有墙
1/表示西面有墙
所以我们可以设一个布尔类型三维数组
a
[
i
,
j
,
4
]
a[i,j,4]
a[i,j,4]
表示第
i
i
i行第
j
j
j列西,北,东,南分别有木有墙。
那么问题来了:如何对每一位进行判断?
c++有一套特别神奇的东西,叫位运算。
用它们就可以进行对每一个二进制位的运算。
在这里,我假设你们都明白它们的作用,我们就可以将运算简化为这样:
for(int i=1;i<=m;i++)
for(register int j=1;j<=n;j++)
{
cin>>x;
for(int v=1;v<=4;v++) a[i][j][v]=1<<(v-1)&x;
}
第一部分(城堡的房间数目,最大的房间的大小)
这两个简单,可以直接一波BFS搞定
对BFS过的点进行标记,如果出现有未搜过的点就进行一次广搜并将计数器加一
上这一片段代码
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
if(!a[i][j][0])
{
y=1;
++d;
q.push((tt){i,j});
while(!q.empty())
{
ww=q.front();
q.pop();
for(register int k=1;k<=4;k++)
if(!a[ww.x][ww.y][k]&&!b[ww.x+dx[k]][ww.y+dy[k]])
{
a[ww.x+dx[k]][ww.y+dy[k]][0]=1;
y++;
q.push((tt){ww.x+dx[k],ww.y+dy[k]});
}
}
if(y>ans1) ans1=y;
}
cout<<d<<endl<<ans1<<endl;
第一部分结束!
第二部分(移除一面墙能得到的最大的房间的大小,移除哪面墙可以得到面积最大的新房间)
这一部分才是真正的毒瘤。
首先我们来考虑下如何判断得到房间面积最大
其实这也不难,我们只需要枚举每一面墙,然后判断它隔开的两个正方形是否属于同一个房间。
那么如何判断呢?
我们考虑前面的BFS,发现它可以计算出这个房间的正方形数量,还只枚举了每一个房间内的正方形!
那么这就好办了,只需在每个正方形入队时对它进行赋值,就可以完成目的!
修改后的BFS如下
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
if(!a[i][j][0])
{
y=1;
b[i][j]=++d;
q.push((tt){i,j});
while(!q.empty())
{
ww=q.front();
q.pop();
for(register int k=1;k<=4;k++)
if(!a[ww.x][ww.y][k]&&!b[ww.x+dx[k]][ww.y+dy[k]])
{
b[ww.x+dx[k]][ww.y+dy[k]]=d;
a[ww.x+dx[k]][ww.y+dy[k]][0]=1;
y++;
q.push((tt){ww.x+dx[k],ww.y+dy[k]});
}
}
c[d]=y;
if(y>ans1) ans1=y;
}
其中
b
[
i
,
j
]
b[i,j]
b[i,j]代表第
i
i
i行第
j
j
j列属于哪个房间。
c
[
i
]
c[i]
c[i]代表第
i
i
i个房间的正方形个数。
最后来解决如何判断移除哪面墙
判断的顺序有点令人懵圈,是如下方案:
^^^^^ ^^^
| | | | | | | |
| | | | | | | |
---------->
图有点粗糙,请不要见怪
也就是说先后顺序为这样
for(int j=1;j<=n;j++)
for(int i=m;i>=1;i--)
接下来是处理最大房间和。
前面的BFS已经处理了每一个正方形所在房间的正方形个数,直接调用便是。
代码
for(int j=1;j<=n;j++)
for(int i=m;i>=1;i--)
for(register int k=2;k<=3;k++)
if(a[i][j][k]&&b[i][j]!=b[i+dx[k]][j+dy[k]]&&c[b[i][j]]+c[b[i+dx[k]][j+dy[k]]]>ans2)
{
ans2=c[b[i][j]]+c[b[i+dx[k]][j+dy[k]]];
ans3=i;
ans4=j;
ans5=k;
}
cout<<ans2<<endl<<ans3<<' '<<ans4<<' '<<cc[ans5]<<endl;
全部合起来就是如下:
#include<bits/stdc++.h>
using namespace std;
bool a[100][100][5];
int dx[5]={0,0,-1,0,1};
int dy[5]={0,-1,0,1,0};
int b[100][100],c[10000],d,e,f,g,m,n,ans1,ans2,ans3,ans4,ans5;
char cc[5]="ACNE";//其实前两个可以随便打
struct tt{
int x,y;
}ww;
queue<tt>q;
int main()
{
int x,y,z;
cin>>n>>m;
for(int i=1;i<=m;i++)
for(register int j=1;j<=n;j++)
{
cin>>x;
for(int v=1;v<=4;v++) a[i][j][v]=1<<(v-1)&x;
}
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
if(!a[i][j][0])
{
y=1;
b[i][j]=++d;
q.push((tt){i,j});
while(!q.empty())
{
ww=q.front();
q.pop();
for(register int k=1;k<=4;k++)
if(!a[ww.x][ww.y][k]&&!b[ww.x+dx[k]][ww.y+dy[k]])
{
b[ww.x+dx[k]][ww.y+dy[k]]=d;
a[ww.x+dx[k]][ww.y+dy[k]][0]=1;
y++;
q.push((tt){ww.x+dx[k],ww.y+dy[k]});
}
}
c[d]=y;
if(y>ans1) ans1=y;
}
cout<<d<<endl<<ans1<<endl;
for(int j=1;j<=n;j++)
for(int i=m;i>=1;i--)
for(register int k=2;k<=3;k++)
if(a[i][j][k]&&b[i][j]!=b[i+dx[k]][j+dy[k]]&&c[b[i][j]]+c[b[i+dx[k]][j+dy[k]]]>ans2)
{
ans2=c[b[i][j]]+c[b[i+dx[k]][j+dy[k]]];
ans3=i;
ans4=j;
ans5=k;
}
cout<<ans2<<endl<<ans3<<' '<<ans4<<' '<<cc[ans5]<<endl;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!