C ++ 11, 6-8 นาที
การทดสอบของฉันใช้เวลาประมาณ 6-8 นาทีในเครื่อง Fedora 19, i5 ของฉัน แต่เนื่องจากการสุ่มของการกลายพันธุ์มันอาจจะเร็วกว่าหรือใช้เวลานานกว่านั้น ฉันคิดว่าเกณฑ์การให้คะแนนต้องได้รับการใส่ใหม่
พิมพ์ผลลัพธ์เป็นข้อความเมื่อเสร็จสิ้นบุคคลที่มีสุขภาพแสดงโดย dot ( .
) ผู้ติดเชื้อโดยเครื่องหมายดอกจัน ( *
) ยกเว้นว่าANIMATE
ตั้งค่าสถานะเป็นจริงในกรณีนี้จะแสดงอักขระที่แตกต่างกันสำหรับผู้ติดเชื้อไวรัสที่แตกต่างกัน
นี่คือ GIF สำหรับ 10x10, 200 คาบ
พฤติกรรมการกลายพันธุ์
การกลายพันธุ์แต่ละครั้งจะให้สายพันธุ์ใหม่ที่ไม่เคยเห็นมาก่อน (ดังนั้นจึงเป็นไปได้ที่คนคนหนึ่งจะติดเชื้อสี่คนที่อยู่ใกล้เคียงกับ 4 สายพันธุ์ที่แตกต่างกัน) เว้นแต่จะมี 800 สายพันธุ์ที่ถูกสร้างขึ้น
ผลลัพธ์ 8 นาทีมาจากผู้ติดเชื้อจำนวนต่อไปนี้:
ช่วงเวลา 0, ติดเชื้อ: 4
ช่วงเวลา 100, ติดเชื้อ: 53743
ช่วงเวลา 200, ติดเชื้อ: 134451
ช่วงเวลา 300, ติดเชื้อ: 173369
ช่วงเวลา 400, ติดเชื้อ: 228176
ช่วงเวลา 500, ติดเชื้อ: 261473
งวด 600, ติดเชื้อ: 276086
ช่วงเวลา 700, ติดเชื้อ: 265774
ช่วงเวลา 800, ติดเชื้อ: 236828
งวด 900, ติดเชื้อ: 221275
ในขณะที่ผลลัพธ์ 6 นาทีมาจากต่อไปนี้:
ช่วงเวลา 0, ติดเชื้อ: 4
ช่วงเวลา 100 ติดเชื้อ: 53627
ช่วงเวลา 200, ติดเชื้อ: 129033
ช่วงเวลา 300, ติดเชื้อ: 186127
ช่วงเวลา 400, ติดเชื้อ: 213633
ช่วงเวลา 500, ติดเชื้อ: 193702
งวด 600, ติดเชื้อ: 173995
ช่วงเวลา 700, ติดเชื้อ: 157966
ช่วงเวลา 800, ติดเชื้อ: 138281
ช่วงเวลา 900, ติดเชื้อ: 129381
ตัวแทนบุคคล
แต่ละคนมีจำนวน 205 ไบต์ สี่ไบต์เพื่อจัดเก็บชนิดไวรัสที่บุคคลนี้กำลังทำสัญญาหนึ่งไบต์เพื่อเก็บระยะเวลาที่บุคคลนั้นติดเชื้อนี้และอีก 200 ไบต์เพื่อเก็บจำนวนครั้งที่เขาติดเชื้อไวรัสแต่ละสายพันธุ์ (2 บิตต่อครั้ง) บางทีอาจมีการจัดแนวไบต์เพิ่มเติมโดย C ++ แต่ขนาดโดยรวมจะอยู่ที่ประมาณ 200MB ฉันมีสองกริดเพื่อเก็บขั้นตอนต่อไปดังนั้นทั้งหมดจะใช้ประมาณ 400MB
ฉันจัดเก็บตำแหน่งของผู้ติดเชื้อในคิวเพื่อลดเวลาที่ต้องใช้ในช่วงต้น (ซึ่งมีประโยชน์จริง ๆ ในช่วง <400)
โปรแกรมทางเทคนิค
ทุก ๆ 100 ขั้นตอนโปรแกรมนี้จะพิมพ์จำนวนผู้ติดไวรัสยกเว้นว่าANIMATE
ตั้งค่าสถานะเป็นtrue
ซึ่งในกรณีนี้โปรแกรมจะพิมพ์ทั้งกริดทุก ๆ 100ms
สิ่งนี้ต้องใช้ไลบรารี C ++ 11 (คอมไพล์โดยใช้-std=c++11
แฟล็กหรือใน Mac ด้วยclang++ -std=c++11 -stdlib=libc++ virus_spread.cpp -o virus_spread
)
เรียกใช้โดยไม่มีอาร์กิวเมนต์สำหรับค่าเริ่มต้นหรือด้วยอาร์กิวเมนต์ดังนี้
./virus_spread 1 0.01 1000
#include <cstdio>
#include <cstring>
#include <random>
#include <cstdlib>
#include <utility>
#include <iostream>
#include <deque>
#include <cmath>
#include <functional>
#include <unistd.h>
typedef std::pair<int, int> pair;
typedef std::deque<pair> queue;
const bool ANIMATE = false;
const int MY_RAND_MAX = 999999;
std::default_random_engine generator(time(0));
std::uniform_int_distribution<int> distInt(0, MY_RAND_MAX);
auto randint = std::bind(distInt, generator);
std::uniform_real_distribution<double> distReal(0, 1);
auto randreal = std::bind(distReal, generator);
const int VIRUS_TYPE_COUNT = 800;
const int SIZE = 1000;
const int VIRUS_START_COUNT = 4;
typedef struct Person{
int virusType;
char time;
uint32_t immune[VIRUS_TYPE_COUNT/16];
} Person;
Person people[SIZE][SIZE];
Person tmp[SIZE][SIZE];
queue infecteds;
double transmissionProb = 1.0;
double mutationProb = 0.01;
int periods = 1000;
char inline getTime(Person person){
return person.time;
}
char inline getTime(int row, int col){
return getTime(people[row][col]);
}
Person inline setTime(Person person, char time){
person.time = time;
return person;
}
Person inline addImmune(Person person, uint32_t type){
person.immune[type/16] += 1 << (2*(type % 16));
return person;
}
bool inline infected(Person person){
return getTime(person) > 0;
}
bool inline infected(int row, int col){
return infected(tmp[row][col]);
}
bool inline immune(Person person, uint32_t type){
return (person.immune[type/16] >> (2*(type % 16)) & 3) == 3;
}
bool inline immune(int row, int col, uint32_t type){
return immune(people[row][col], type);
}
Person inline infect(Person person, uint32_t type){
person.time = 1;
person.virusType = type;
return person;
}
bool inline infect(int row, int col, uint32_t type){
auto person = people[row][col];
auto tmpPerson = tmp[row][col];
if(infected(tmpPerson) || immune(tmpPerson, type) || infected(person) || immune(person, type)) return false;
person = infect(person, type);
infecteds.push_back(std::make_pair(row, col));
tmp[row][col] = person;
return true;
}
uint32_t inline getType(Person person){
return person.virusType;
}
uint32_t inline getType(int row, int col){
return getType(people[row][col]);
}
void print(){
for(int row=0; row < SIZE; row++){
for(int col=0; col < SIZE; col++){
printf("%c", infected(row, col) ? (ANIMATE ? getType(row, col)+48 : '*') : '.');
}
printf("\n");
}
}
void move(){
for(int row=0; row<SIZE; ++row){
for(int col=0; col<SIZE; ++col){
people[row][col] = tmp[row][col];
}
}
}
int main(const int argc, const char **argv){
if(argc > 3){
transmissionProb = std::stod(argv[1]);
mutationProb = std::stod(argv[2]);
periods = atoi(argv[3]);
}
int row, col, size;
uint32_t type, newType=0;
char time;
Person person;
memset(people, 0, sizeof(people));
for(int row=0; row<SIZE; ++row){
for(int col=0; col<SIZE; ++col){
people[row][col] = {};
}
}
for(int i=0; i<VIRUS_START_COUNT; i++){
row = randint() % SIZE;
col = randint() % SIZE;
if(!infected(row, col)){
infect(row, col, 0);
} else {
i--;
}
}
move();
if(ANIMATE){
print();
}
for(int period=0; period < periods; ++period){
size = infecteds.size();
for(int i=0; i<size; ++i){
pair it = infecteds.front();
infecteds.pop_front();
row = it.first;
col = it.second;
person = people[row][col];
time = getTime(person);
if(time == 0) continue;
type = getType(person);
if(row > 0 && randreal() < transmissionProb){
if(newType < VIRUS_TYPE_COUNT-1 && randreal() < mutationProb){
newType++;
if(!infect(row-1, col, newType)) newType--;
} else {
infect(row-1, col, type);
}
}
if(row < SIZE-1 && randreal() < transmissionProb){
if(newType < VIRUS_TYPE_COUNT-1 && randreal() < mutationProb){
newType++;
if(!infect(row+1, col, newType)) newType--;
} else {
infect(row+1, col, type);
}
}
if(col > 0 && randreal() < transmissionProb){
if(newType < VIRUS_TYPE_COUNT-1 && randreal() < mutationProb){
newType++;
if(!infect(row, col-1, newType)) newType--;
} else {
infect(row, col-1, type);
}
}
if(col < SIZE-1 && randreal() < transmissionProb){
if(newType < VIRUS_TYPE_COUNT-1 && randreal() < mutationProb){
newType++;
if(!infect(row, col+1, newType)) newType--;
} else {
infect(row, col+1, type);
}
}
time += 1;
if(time == 4) time = 0;
person = setTime(person, time);
if(time == 0){
person = addImmune(person, type);
} else {
infecteds.push_back(std::make_pair(row, col));
}
tmp[row][col] = person;
}
if(!ANIMATE && period % 100 == 0) printf("Period %d, Size: %d\n", period, size);
move();
if(ANIMATE){
printf("\n");
print();
usleep(100000);
}
}
if(!ANIMATE){
print();
}
return 0;
}