欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

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

发布时间:2025/3/17 编程问答 49 豆豆
生活随笔 收集整理的这篇文章主要介绍了 信息学奥赛一本通 1191:流感传染 | OpenJudge NOI 2.3 6262:流感传染 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

【题目链接】

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

【题目考点】

1. 二维数组

2. 队列

【解题思路】

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

1. 多趟遍历二维数组

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

2. 队列优化

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

总结

以上是生活随笔为你收集整理的信息学奥赛一本通 1191:流感传染 | OpenJudge NOI 2.3 6262:流感传染的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。