C ++ 11, 6-8 phút
Quá trình chạy thử của tôi mất khoảng 6-8 phút trong máy Fedora 19, i5 của tôi. Nhưng do tính ngẫu nhiên của đột biến, nó có thể nhanh hơn hoặc mất nhiều thời gian hơn thế. Tôi nghĩ rằng các tiêu chí chấm điểm cần phải được đánh giá lại.
In kết quả dưới dạng văn bản khi kết thúc hoàn thành, người khỏe mạnh được biểu thị bằng dấu chấm ( .
), người bị nhiễm bởi dấu hoa thị ( *
), trừ khi ANIMATE
cờ được đặt thành đúng, trong trường hợp đó, nó sẽ hiển thị các ký tự khác nhau cho những người bị nhiễm các chủng virus khác nhau.
Đây là một GIF cho 10 x 10, 200 tiết.
Hành vi đột biến
Mỗi đột biến sẽ tạo ra chủng mới chưa từng thấy trước đây (vì vậy có thể một người lây nhiễm cho bốn người lân cận với 4 chủng khác nhau), trừ khi 800 chủng đã được tạo ra, trong trường hợp đó, virus sẽ không bị đột biến thêm nữa.
Kết quả 8 phút đến từ số người nhiễm bệnh sau đây:
Thời kỳ 0, bị nhiễm bệnh: 4
Thời kỳ 100, bị nhiễm bệnh: 53743
Thời kỳ 200, bị nhiễm bệnh: 134451
Thời kỳ 300, bị nhiễm bệnh: 173369
Thời kỳ 400, bị nhiễm bệnh: 228176
Kỳ 500, bị nhiễm: 261473
Thời kỳ 600, bị nhiễm bệnh: 276086
Thời kỳ 700, bị nhiễm bệnh: 265774
Thời kỳ 800, bị nhiễm bệnh: 236828
Thời kỳ 900, bị nhiễm bệnh: 221275
trong khi kết quả 6 phút đến từ các mục sau:
Thời kỳ 0, bị nhiễm bệnh: 4
Thời kỳ 100, bị nhiễm bệnh: 53627
Thời kỳ 200, bị nhiễm bệnh: 129033
Thời kỳ 300, bị nhiễm bệnh: 186127
Thời kỳ 400, bị nhiễm bệnh: 213633
Thời kỳ 500, bị nhiễm bệnh: 193702
Thời kỳ 600, bị nhiễm bệnh: 173995
Thời kỳ 700, bị nhiễm bệnh: 157966
Giai đoạn 800, bị nhiễm bệnh: 138281
Thời kỳ 900, bị nhiễm bệnh: 129381
Đại diện cá nhân
Mỗi người được đại diện trong 205 byte. Bốn byte để lưu trữ loại vi-rút mà người này đang mắc phải, một byte để lưu trữ người này đã bị nhiễm bệnh bao lâu và 200 byte để lưu trữ số lần anh ta nhiễm mỗi chủng vi-rút (mỗi loại 2 bit). Có lẽ có một số căn chỉnh byte bổ sung được thực hiện bởi C ++, nhưng tổng kích thước sẽ vào khoảng 200MB. Tôi có hai lưới để lưu trữ bước tiếp theo, vì vậy tổng cộng nó sử dụng khoảng 400MB.
Tôi lưu trữ vị trí của những người bị nhiễm trong hàng đợi, để cắt giảm thời gian cần thiết trong giai đoạn đầu (điều này thực sự hữu ích cho đến khoảng thời gian <400).
Chương trình kỹ thuật
Cứ sau 100 bước chương trình này sẽ in số người bị nhiễm, trừ khi ANIMATE
cờ được đặt thành true
, trong trường hợp đó, nó sẽ in toàn bộ lưới sau mỗi 100ms.
Điều này đòi hỏi các thư viện C ++ 11 (biên dịch bằng -std=c++11
cờ hoặc trong Mac với clang++ -std=c++11 -stdlib=libc++ virus_spread.cpp -o virus_spread
).
Chạy nó mà không có đối số cho các giá trị mặc định hoặc với các đối số như thế này:
./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;
}