#include <queue>
#include <iostream>
#include <memory>
#include <vector>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#define VEC_INIT_CAPACITY 100
#define MATRIX_AT(matrix, i, j) (matrix)[(i) * COLS + (j)]
static size_t ROWS = 1;
static size_t COLS = 1;
static const uint32_t COLORS_NUM = 3;
static uint64_t SEED = 0xDEADBEEFull;
static uint64_t next = SEED;
uint32_t LCGRand()
{
next = next * 6364136223846793005 + 1442695040888963407;
return next >> 32;
}
struct Block {
typedef std::shared_ptr<Block> Ptr;
uint32_t color;
size_t size;
Ptr redir;
};
size_t main_cpp()
{
std::vector<Block::Ptr> up_row(COLS);
size_t max_size = 0;
clock_t start = clock();
for (size_t row = 0; row < ROWS; row++) {
Block::Ptr left;
for (size_t col = 0; col < COLS; col++) {
uint32_t color = LCGRand() % COLORS_NUM;
Block::Ptr &up = up_row[col];
while (up && up->redir)
up = up->redir;
Block::Ptr cur;
if (left && (left->color == color)) {
cur = left;
if (up && (up->color == color) && (up != left)) {
left->size += up->size;
up->redir = left;
}
} else if (up && (up->color == color)) {
cur = up;
} else {
cur = std::make_shared<Block>(Block{ color, 0, nullptr });
}
max_size = std::max(max_size, ++cur->size);
left = up = cur;
}
}
//std::cout << "Max block size: " << max_size << std::endl
// << "Time: " << (clock() - start) / (CLOCKS_PER_SEC / 1000) << " ms" << std::endl;
return max_size;
}
typedef struct Node_s {
uint32_t color;
uint32_t isVisited;
} Node;
typedef struct Coords_s {
intptr_t i;
intptr_t j;
} Coords;
typedef struct Vec_s {
Coords *arr;
size_t curSize;
size_t curCapacity;
} Vec;
Vec *vec_create()
{
Vec *vec = (Vec*)malloc(sizeof(Vec));
if (!vec) {
return NULL;
}
vec->arr = (Coords*)malloc(VEC_INIT_CAPACITY * sizeof(Coords));
if (!vec->arr) {
free(vec);
return NULL;
}
vec->curCapacity = VEC_INIT_CAPACITY;
vec->curSize = 0;
return vec;
}
int vec_push(Vec *vec, intptr_t i, intptr_t j)
{
if (vec->curSize >= vec->curCapacity) {
size_t newCapacity = vec->curCapacity * 2;
Coords *oldArr = vec->arr;
vec->arr = (Coords*)realloc(vec->arr, newCapacity * sizeof(Coords));
if (!vec->arr) {
vec->arr = oldArr;
return 0;
}
vec->curCapacity = newCapacity;
}
vec->arr[vec->curSize].i = i;
vec->arr[vec->curSize].j = j;
vec->curSize++;
return 1;
}
Coords *vec_pop(Vec *vec)
{
if (vec->curSize > 0) {
return &vec->arr[vec->curSize-- - 1];
} else {
return NULL;
}
}
void vec_clear(Vec *vec)
{
vec->curSize = 0;
}
void vec_delete(Vec *vec)
{
if (vec) {
if (vec->arr) {
free(vec->arr);
}
free(vec);
}
}
inline int isValidCoords(intptr_t i, intptr_t j)
{
return (i >= 0) && (i < ROWS) && (j >= 0) && (j < COLS);
}
size_t visitNode(Node *matrix, intptr_t i, intptr_t j)
{
static const int MOVES[][2] = {
{ -1, 0 },
{ +1, 0 },
{ 0, -1 },
{ 0, +1 },
};
size_t blockSize = 0;
uint32_t targetColor = MATRIX_AT(matrix, i, j).color;
static Vec *vec = NULL;
if (!vec) {
vec = vec_create();
if (!vec) {
goto OOM;
}
}
if (!vec_push(vec, i, j)) {
goto OOM;
}
MATRIX_AT(matrix, i, j).isVisited = 1;
while (vec->curSize > 0) {
Coords *coords = vec_pop(vec);
i = coords->i;
j = coords->j;
blockSize++;
for (size_t moveIdx = 0; moveIdx < sizeof(MOVES) / sizeof(MOVES[0]); moveIdx++) {
intptr_t movedI = i + MOVES[moveIdx][0], movedJ = j + MOVES[moveIdx][1];
if (isValidCoords(movedI, movedJ)) {
Node *adjNode = &MATRIX_AT(matrix, movedI, movedJ);
if (adjNode->color == targetColor && !adjNode->isVisited) {
adjNode->isVisited = 1;
if (!vec_push(vec, movedI, movedJ)) {
goto OOM;
}
}
}
}
}
vec_clear(vec);
return blockSize;
OOM:
perror("OOM");
vec_delete(vec);
exit(EXIT_FAILURE);
}
void print_matrix(Node *matrix)
{
for (size_t i = 0; i < ROWS; i++) {
for (size_t j = 0; j < COLS; j++) {
putchar(MATRIX_AT(matrix, i, j).color + '0');
}
putchar('\n');
}
}
size_t main_c()
{
Node *matrix = (Node*)calloc(ROWS * COLS, sizeof(Node));
for (size_t i = 0; i < ROWS * COLS; i++) {
matrix[i].color = LCGRand() % COLORS_NUM;
}
//print_matrix(matrix);
clock_t start = clock();
size_t maxAdjNodes = 0;
for (intptr_t i = 0; i < ROWS; i++) {
for (intptr_t j = 0; j < COLS; j++) {
if (!MATRIX_AT(matrix, i, j).isVisited) {
size_t adjNodes = visitNode(matrix, i, j);
if (maxAdjNodes < adjNodes) {
maxAdjNodes = adjNodes;
}
}
}
}
free(matrix);
//printf("Max block size: %zd\ntime: %ld", maxAdjNodes, (clock() - start) / (CLOCKS_PER_SEC / 1000));
return maxAdjNodes;
}
int main()
{
for (ROWS = 1; ROWS < 10; ROWS++) {
for (COLS = 1; COLS < 100; COLS++) {
for (int i = -5; i < 5; i++) {
next = SEED + i;
size_t res_c = main_c();
next = SEED + i;
size_t res_cpp = main_cpp();
if (res_c != res_cpp) {
std::cout << "ERROR FOR SEED = " << SEED + i
<< ", ROWS = " << ROWS << ", COLS = " << COLS << "(" << res_c << " != " << res_cpp << ")" << std::endl;
return EXIT_FAILURE;
}
}
}
}
std::cout << "OK" << std::endl;
return EXIT_SUCCESS;
}