计算机病毒传播模拟:如何让每次试验输出随机化?
病毒传播模拟代码问题排查与修复
问题根源分析
所有试验输出完全相同的问题,核心来自三类逻辑错误:
- 清除时间固定为2天:
t++被放在while循环外部,无论循环执行多少次,最终t只会是初始值1+1=2;感染数更新逻辑错误,直接用新增感染数覆盖原有感染数,完全不符合传播规律;清除操作只是单纯减数字,没有实际跟踪感染状态,随机性无效。 - 后两个结果无随机性:原代码调用的
calculateProbAnyComputerInfected和calculateExpectedInfectedComputers是计算固定理论值的函数,输入参数不变,返回结果自然一致,和当前试验的随机过程无关。
修正后的代码
import java.util.Arrays; import java.util.Random; public class VirusSpreadSimulation { public static void main(String[] args) { int numTrials = 5; int numComputers = 20; double pSpread = 0.1; int numInitialInfected = 1; int numToRemove = 5; int[] timesToRemoveVirus = new int[numTrials]; double[] probAnyComputerInfected = new double[numTrials]; int[] actualInfectedCounts = new int[numTrials]; for (int trial = 0; trial < numTrials; trial++) { Random random = new Random(); // 跟踪每台计算机是否曾被感染过 boolean[] everInfected = new boolean[numComputers]; // 跟踪当前处于感染状态的计算机 boolean[] currentlyInfected = new boolean[numComputers]; // 初始化:随机选一台计算机作为初始感染源 int initialIdx = random.nextInt(numComputers); currentlyInfected[initialIdx] = true; everInfected[initialIdx] = true; int numInfected = numInitialInfected; int t = 0; while (numInfected > 0) { t++; // 每循环一次代表过去一天,先更新天数 int newInfections = 0; // 模拟病毒传播:当前感染的计算机尝试向未感染的机器传播 for (int i = 0; i < numComputers; i++) { if (currentlyInfected[i]) { // 遍历所有未被感染的计算机 for (int j = 0; j < numComputers; j++) { if (!currentlyInfected[j] && !everInfected[j]) { if (random.nextDouble() < pSpread) { currentlyInfected[j] = true; everInfected[j] = true; newInfections++; } } } } } numInfected += newInfections; // 模拟清除操作:随机清除最多numToRemove台当前感染的计算机 int removed = 0; while (removed < numToRemove && numInfected > 0) { int randomIdx = random.nextInt(numComputers); if (currentlyInfected[randomIdx]) { currentlyInfected[randomIdx] = false; numInfected--; removed++; } } } // 记录当前试验的实际结果 timesToRemoveVirus[trial] = t; int everInfectedCount = (int) Arrays.stream(everInfected).filter(b -> b).count(); probAnyComputerInfected[trial] = (double) everInfectedCount / numComputers; actualInfectedCounts[trial] = everInfectedCount; // 输出单试验结果 System.out.println("第" + (trial + 1) + "次试验: "); System.out.println("清除病毒所需时间: " + timesToRemoveVirus[trial] + " 天"); System.out.println("单台计算机至少被感染一次的概率: " + probAnyComputerInfected[trial]); System.out.println("实际感染过的计算机数量: " + actualInfectedCounts[trial]); System.out.println(); } // 计算并输出所有试验的平均值 double averageTime = Arrays.stream(timesToRemoveVirus).average().orElse(0); double averageProb = Arrays.stream(probAnyComputerInfected).average().orElse(0); double averageInfectedCount = Arrays.stream(actualInfectedCounts).average().orElse(0); System.out.println("试验次数: " + numTrials); System.out.println("平均清除时间: " + averageTime + " 天"); System.out.println("平均单台感染概率: " + averageProb); System.out.println("平均感染计算机数量: " + averageInfectedCount); } }
关键修改点说明
- 修复时间统计:把
t++移到while循环内部,每次循环代表一天,正确统计清除病毒的实际天数。 - 精准跟踪感染状态:用
currentlyInfected和everInfected两个数组分别记录当前感染和曾被感染的计算机,解决原代码中感染数更新逻辑混乱的问题。 - 真实模拟传播过程:遍历所有当前感染的计算机,每台尝试向未感染的机器传播,符合病毒传播的实际逻辑。
- 有效模拟清除操作:随机选择当前感染的计算机进行清除,直到达到清除数量上限或无感染机器,保证清除操作的随机性。
- 统计试验实际数据:不再依赖固定公式计算理论值,而是从当前试验的感染状态数组中统计实际结果,确保每次试验输出的随机性。
内容的提问来源于stack exchange,提问作者Amir Goziyev
相关产品推荐
相关产品推荐

