命题人:ww
知识点:bfs+多队列
难度:中档
时间限制:1000ms
内存限制:65536KiB
食堂买饭
#### Description 题面描述: acmer今天要从实验室去食堂买包子回来,实验室的教学楼到超市之间有一条漆黑的路,路是用黑色或者白色的地板铺成的,acmer看不清黑色的地板,只能看清白色的地板,acmer需要照亮黑色的地板后才能走到该位置,白色地板则不需要。 acmer用来照亮的是一个破旧的手电筒,他需要预先充电才能使用(电量初始为零),因为太过于破旧,照亮一块地板之后手电筒的电量会下降一格。假如手电筒的电量不封顶,问acmer最少需要充多少电才能走到食堂买到包子。 这条路的一头是实验室对应所有横坐标为零的地板且地板,另一头是食堂,对应所有横坐标位n+1的地板。 问acmer最少需要充多少电才能从实验室走到食堂。 提示:acmer只能从一个地板走到有相邻边的地板(可以上下左右走)。 #### Input 输入 第一行输入n和m代表整条路的长度1<=n<=50,与宽度1<=m<=100000; 下面第二道n+1行每行m个数,只由0和1组成,1代表黑色的地板,0代表白色的地板。 #### Output 输出 输出一个数至少充多少电量。 #### Sample ##### Input ```in 输入数据 10 10 6 4 1 0 0 1 0 1 0 1 0 0 1 0 0 1 1 1 1 0 1 0 1 1 0 1 ``` ##### Output ```out 输出数据 3 ``` #### Hint 提示 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-61gRFYSI-1624706825955)(en-resource://database/535:1)]#include <cstdio>
#include <algorithm>
#include <queue>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
int dx[]={-1,0,1,0};
int dy[]={0,1,0,-1};
const int maxn=1200;
int g[maxn][maxn];
int vis[maxn][maxn];
int n,m;
int ans=0;
void solve()
{
queue<PII> q[n+10];
for(int i=1;i<=m;i++)
{
vis[1][i]=g[1][i];
if(g[1][i])
q[1].push({1,i});
else
q[0].push({1,i});
}
for(int i=0;i<=n;i++)
{
while(q[i].size())
{
PII u=q[i].front();
q[i].pop();
if(u.first==n)break;
int step=vis[u.x][u.y];
for(int j=0;j<4;j++)
{
int xx=u.x+dx[j];
int yy=u.y+dy[j];
if(xx<=1||xx>n||yy<1||yy>m)continue;
if(vis[xx][yy]==n+10)
{
vis[xx][yy]=step;
if(g[xx][yy])
vis[xx][yy]++;
q[vis[xx][yy]].push({xx,yy});
}
}
}
}
ans=n+10;
for(int i=1;i<=m;i++)
{
ans=min(ans,vis[n][i]);
}
return ;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
scanf("%d",&g[i][j]);
vis[i][j]=n+10;
}
}
solve();
printf("%d\n",ans);
return 0;
}
出题组建议:
公式,变量和计算用的数据使用 LaTeX 公式,
中文英文之间要加空格
错误:使用LaTeX公式
正确:使用 LaTeX 公式
中文和数字之间要加空格
数字和单位之间要加空格
标点使用全角符号
全角标点与其他字符不需要加空格
模板中已有的 HTML 标签不需要删除。
一.题意:
给定一个条路,路由黑色或者白色的格子铺成。
问,如何从最上面一行走到最下面一行踩到的黑色格子最少?,输出最少需要踩多少黑色格子的数量。(第一行任意一个格子作为开始位置,第n行任意一个格子作为结束位置)
二.解法:需要开至少是n重的多队列,用于bfs中存储该格子是最少需要踩多少黑色格子才能到达的点。根据踩黑色格子数量的大小先遍历完最少的那个,中间如果先遇到第n行的格子,直接跳出。因为多重队列式的bfs同bfs一样先遍历最小的值,所以满足最先遍历到的第n行的那个格子所需要的踩黑色格子已经是最优解。
三.对于第一行,将所有格子先放入多重队列中,是 0 先放入 0 队列,是 1 先放入 1 队列。最后遍历完所有队列中的节点就可以得到需要的答案,时间复杂度O(G)图中节点数量。
用dijkstra一开始加入所有起点虽然也可以得到正确答案,设优先队列中节点个数为L,那么会增加log(L)*G的复杂度。L数据至少可以卡到m数量级。
四:图中的数字 0 , 1 可以用字符方式读入,getchar会比较快。
#include <algorithm>
#include <cstdio>
#include <queue>
using namespace std;
#define x first
#define y second
typedef pair<int, int> PII;
int dx[] = {-1, 0, 1, 0};
int dy[] = {0, 1, 0, -1};
const int maxn1 = 52,maxn2=100010;;
int g[maxn1][maxn2];
int vis[maxn1][maxn2];
int n, m;
int ans = 0;
void solve() {
queue<PII> q[n + 10];
for (int i = 1; i <= m; i++) {
vis[1][i] = g[1][i];
if (g[1][i])
q[1].push({1, i});
else
q[0].push({1, i});
}
for (int i = 0; i <= n; i++) {
while (q[i].size()) {
PII u = q[i].front();
q[i].pop();
if (u.first == n) break;
int step = vis[u.x][u.y];
for (int j = 0; j < 4; j++) {
int xx = u.x + dx[j];
int yy = u.y + dy[j];
if (xx <= 1 || xx > n || yy < 1 || yy > m) continue;
if (vis[xx][yy] == n + 10) {
vis[xx][yy] = step;
if (g[xx][yy]) vis[xx][yy]++;
q[vis[xx][yy]].push({xx, yy});
}
}
}
}
ans = n + 10;
for (int i = 1; i <= m; i++) {
ans = min(ans, vis[n][i]);
}
return;
}
int main() {
scanf("%d%d\n", &n, &m);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
// scanf("%d", &g[i][j]);
char ch = getchar();
g[i][j] = ch - '0';
getchar();
vis[i][j] = n + 10;
}
}
solve();
printf("%d\n", ans);
return 0;
}