信息学奥赛一本通 1191:流感传染 | OpenJudge NOI 2.3 6262:流感传染

【题目链接】

ybt 1191:流感传染
OpenJudge NOI 2.3 6262:流感传染

【题目考点】

1. 二维数组
2. 队列

【解题思路】

用一个字符型二维数组存储各个房间的情况。

1. 多趟遍历二维数组

每一天遍历整个二维数组,如果当前房间有健康的人'.',而周围房间前一天有患病的人'@',那么当前房间的人在这一天也会患病。
更新过程中,可以设临时数组保存新的一天的情况,然后再拷贝给原数组。
循环16次,而后统计整个二维数组中患病的人数。
每天都要遍历二维数组,二维数组为n*n,共m天,该算法复杂度为 O ( m ∗ n 2 ) O(m*n^2) O(mn2)
m最大100,n最大为100,最大运算次数达到 1 0 6 10^6 106数量级,是可行的。

2. 队列优化

这一过程有点类似于广搜。
由于一个患病的人第一天已经将周围的人传染,第二天及以后周围的都是患病的人,也就无法再传染给更多的人。只有前一天刚刚被传染的人,在下一天才会传染给别人。
设结构体,保存一个人所在的位置,以及他是第几天被感染的。
设队列保存刚刚患病的人,队列中保存的是上述该结构体类型的对象。
只要队列不空,每次出队一人u,将u周围的人感染,这些人感染被感染的日子是u被感染的日子加1。如果u是第m天被感染的,则不再向外传染。统计出队的元素的个数,即为前m天被感染的人数。
该算法中每个患病的人至多遍历1次,运算复杂度为 O ( n 2 ) O(n^2) O(n2),最大运算次数达到 1 0 4 10^4 104数量级,优于解法1。

题外话:如果学过图论算法,这两种算法间的关系类似于Bellman-ford算法与SPFA算法之间的关系。

【题解代码】

解法1:多趟遍历二维数组
#include <bits/stdc++.h>
using namespace std;
#define N 105
int dir[4][2] = {{0,1},{0,-1},{1,0},{-1,0}};
int main()
{
    char mp[N][N], t[N][N];//t:临时数组 
	int n, m, ct = 0;
	cin >> n;
	for(int i = 1; i <= n; ++i)
        for(int j = 1; j <= n; ++j)
            cin >> mp[i][j];
    cin >> m;
    for(int k = 2; k <= m; ++k)//第k天如何传染 
    {
        memset(t, 0, sizeof(t));//对t清空。 
        for(int i = 1; i <= n; ++i)
            for(int j = 1; j <= n; ++j)
            {
                t[i][j] = mp[i][j];
                if(mp[i][j] == '.')//如果(i,j)没患病,但周围有病人,就会被传染,否则和原来一样。 
                {
                    for(int l = 0; l < 4; ++l)
                    {
                        int x = i + dir[l][0], y = j + dir[l][1];
                        if(x >= 1 && x <= n && y >= 1 && y <= n && mp[x][y] == '@') 
                            t[i][j] = '@';
                    }
                }
            }
        memcpy(mp, t, sizeof(t));//拷贝t到mp 
    }
    for(int i = 1; i <= n; ++i)
        for(int j = 1; j <= n; ++j)
            if(mp[i][j] == '@')
                ct++;
    cout << ct; 
	return 0;
}
解法2:队列优化

该解法使用scanf读入字符型二维数组,因为scanf("%c")会读入换行符,因而要注意吸收换行符。

#include <bits/stdc++.h>
using namespace std;
#define N 105
struct Node
{
    int x, y, d;//x,y:坐标 d:天数
    Node(){}
    Node(int a, int b, int c):x(a),y(b),d(c){}
};
char mp[N][N];
bool vis[N][N];//第i,j位置是否已经被统计过 
int n, m, ct;//ct:计数 
int dir[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
queue<Node> que;//队列 保存刚刚感染的人 
int main()
{
    scanf("%d\n", &n);//如不吸收本行的换行符,这个换行符会被下面的scanf("%c")读入 
    for(int i = 1; i <= n; ++i)
    {
        for(int j = 1; j <= n; ++j)
        {
            scanf("%c", &mp[i][j]);
            if(mp[i][j] == '@')
            {
                que.push(Node(i, j, 1));//感染者入队
                vis[i][j] = true;
                ct++;
            }
        }
        getchar();//注意,scanf("%c")会读入换行符。这里需要用getchar()吸收每行末尾的换行符 
    }
    scanf("%d", &m);
    while(que.empty() == false)
    {
        Node u = que.front();
        que.pop();
        if(u.d == m)//这是个第m天患病的人,不再统计m+1天被传染的人 
            continue;
        for(int i = 0; i < 4; ++i)
        {
            int x = u.x + dir[i][0], y = u.y + dir[i][1], d = u.d + 1;
            if(x >= 1 && x <= n && y >= 1 && y <= n && vis[x][y] == false && mp[x][y] == '.')
            {
                que.push(Node(x, y, d));
                vis[x][y] = true;
                ct++;
            }
        }
    }
    printf("%d", ct);
    return 0;
}
  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
信息学奥赛一本通1255:迷宫问题是一个关于迷宫的问题。这个问题要求通过广搜算法来解决迷宫问题,找到走出迷宫的路径。具体来说,迷宫可以看成是由n×n的格点组成,每个格点只有两种状态, "." 和 "#" 。其中 "." 代表可通行的路径,"#" 代表不可通行的墙壁。通过广搜算法,我们可以搜索从起点到终点的路径,找到一条合法的路径即可。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [信息学奥赛一本通 1255:迷宫问题 | OpenJudge NOI 2.5 7084:迷宫问题](https://blog.csdn.net/lq1990717/article/details/124721407)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [c++信息学奥赛一本通1215题解](https://download.csdn.net/download/Asad_Yuen/87357807)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [信息学奥赛一本通(1255:迷宫问题)](https://blog.csdn.net/lvcheng0309/article/details/118879231)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值