bfs+多队列优化。(自己出题出的后台数据水的很)

命题人: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;
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值