【题目链接】
ybt 1191:流感传染
OpenJudge NOI 2.3 6262:流感传染
【题目考点】
1. 二维数组
2. 队列
【解题思路】
用一个字符型二维数组存储各个房间的情况。
1. 多趟遍历二维数组
每一天遍历整个二维数组,如果当前房间有健康的人'.'
,而周围房间前一天有患病的人'@'
,那么当前房间的人在这一天也会患病。
更新过程中,可以设临时数组保存新的一天的情况,然后再拷贝给原数组。
循环16次,而后统计整个二维数组中患病的人数。
每天都要遍历二维数组,二维数组为n*n,共m天,该算法复杂度为
O
(
m
∗
n
2
)
O(m*n^2)
O(m∗n2)
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;
}