首页 > C/C++ “流感传染”算法问题

C/C++ “流感传染”算法问题


还没有学过算法,感觉用的方法有些笨。
刚学了函数就用上了。
请大神看看有什么可以改进的地方吗,或者有哪些代码不太规范的地方?

而且 vs2015 好像还不支持 变长数组,所以只能定义常量。
有没有大神教一下怎么定义变长数组。

以下是我的代码

#include<iostream>
#include <iomanip>
using namespace std;

const int N = 5;                //定义宿舍边长
char dorm[N][N];                 //定义一个N*N的全局 二维字符数组

int function(int a)
{
    int count = 0;                                             //用来记录所有宿舍共有多少个感染者
    for (int i = 1; i < a; i++)
    {
        for (int i = 0; i < N; i++)
        {
            for (int j = 0; j < N; j++)
            {
                if (dorm[i][j] == '@')                         //找到数组中感染的人“@”。把其上下左右都标为“*”,以避免多算上新患者,避免使新患者周围也被传染。
                {
                    if (i + 1 < N && dorm[i + 1][j] != '#' && dorm[i + 1][j] != '@')   //考虑边界和 空房子的情况
                        dorm[i + 1][j] = '*';
                    if (j + 1 < N && dorm[i][j + 1] != '#' && dorm[i][j + 1] != '@')
                        dorm[i][j + 1] = '*';
                    if (i - 1 >= 0 && dorm[i - 1][j] != '#' && dorm[i - 1][j] != '@')
                        dorm[i - 1][j] = '*';
                    if (j - 1 >= 0 && dorm[i][j - 1] != '#' && dorm[i][j - 1] != '@')
                        dorm[i][j - 1] = '*';
                }
            }
        }
        for (int k = 0; k < N; k++)                    //一次传染完成后,将新传染的“*”赋值为“@”
        {
            for (int h = 0; h < N; h++)
            {
                if (dorm[k][h] == '*')
                    dorm[k][h] = '@';
            }
        }

    }
    for (int i = 0; i < N; i++)                               //统计感染者人数
        for (int j = 0; j < N; j++)
        {
            if (dorm[i][j] == '@')
                count++;
        }
    return count;
}

int main()
{
    cout << "请输入宿舍感染情况矩阵:" << endl;
    for (int i = 0; i < N; i++)
        for (int j = 0; j < N; j++)
            cin >> dorm[i][j];
    int day;                                      //输入第几天
    cout << "请输入第几天:" << endl;
    cin >> day;
    cout << "此时感染人数:" << function(day) << endl;
    cout << "此时感染情况" << endl;
    for (int i = 0; i < N; i++)                   //输出此时的宿舍感染分布情况
    {
        for (int j = 0; j < N; j++)
            cout << dorm[i][j] << ' ';
        cout << endl;
    }

    return 0;
}

N的最大值是一百,你就数组 为
arr101 就行了


可以用位运算。100用2个unsigned long就够了。
unsigned long sick100;//用来表示病人
unsigned long person100;//用来表示有人
每天:
先算sick数组,根据规则上下左右都设置1,
然后跟person进行与操作,排除那些空房子。


@sanix 对于位运算的方法我没看懂,能否讲的更详细点:

  1. 因为是NxN个房间,unsigned long在32位系统是4字节,不知道怎么容纳下每行100个元素?

  2. 根据规则上下左右都设置1这个如何做?

对于时间效率上我的思路:
用空间换时间,可将新增加的感染的人放入一个集合(初始状态是最初感染的人的坐标),每增加一天,就遍历这个集合中的人,在矩阵中找到可以新感染的人,清空这个集合,把新感染的人加入集合中。直到到达指定天数,或者找不到可以新感染的人为止。同时由一个变量increase记录每次新增加的人数。相对你的三层for循环来说有一定的时间优势。

下面写下大概意思的代码:

const int N = 101;
char dorm[N][N];
int day = 输入的天数;
int  x[N*N+1];//记录该天新增病人x坐标
int  y[N*N+1];//y坐标


读入初始化dorm数组,并在遇到病人时,将其在dorm数组中x、y下标分别存入x、y数组,读入完毕,x中下一个元素置为-1作为标记。如初始时有3个病人,则最后x[3]=-1
....
下面计算天数为day时的感染人数
int count = 0;//记录总感染数
p = 0;//x、y数组的指针
q = N*N;
step = 1;//这里用一点小技巧来节省占用空间。把昨天新感染的人和今天新感染的人放入一个x、y数组,一个从0开始往后放,一个从最后一个元素往前放。当step为1时,表明昨天感染的人是从x/y数组前往后放的。
for(int i = 0; i < day; i++)
{
    int increase = 0;//标记当天新增病人
    while(x[p] != -1) 
    {
        判断dorm[x[p]][y[p]]的四个邻居是否可被感染(不为空房子、不为已感染的人),可感染即加入数组,我这里只写一个:假设dorm[a][b]可被感染,则
        x[q] = a; y[q] = b;
        q += -1*step;
        increase++;
        
        //4个方向都判断过后
        p += step;
    }
  
    x[p] = -1;//打个收尾标记
    step = -1*step; p = N*N; q = 0;//换个方向存
    if(increase == 0)
    {
        break;//不会有新病人了,之后的感染人数都不会变化,跳出
    }
    count += increase;
}


输出 count


变长数组用stl里的vector


变长数组是C99的特性,VS2015支持C89/C11和部分C99,不支持变长数组


这个答案仅指出一个对于在线判题而言不规范的地方:这个程序的输入输出太罗嗦了。

如果你的确需要输出一些额外信息,请善加利用cerr标准错误流。

【热门文章】
【热门文章】