Консультация № 181258
12.12.2010, 22:37
52.53 руб.
0 17 1
Здравствуйте, уважаемые эксперты! Прошу Вас ответить на следующий вопрос об очередной задаче о перколяции на кубической решетке:
Перколяция считается по 3 направлениям -горизонтальной, вертикальной и диагональной( ну по оси z то есть). Но есть сложность в заполнении самой решетки : если решетка 10х10х10, то программа считает довольно быстро. Если решетка 20х20х20 то программа зависает(начинает считать КРАЙНЕ медленно) при вероятности заполнения решетки где на 23%. При решетке 50х50х50 - еще раньше.
Думаю, что проблема именно в ее заполнении.
Делала заполнение решетки, как в квадратной, но тогда программа вопще заполнять не хотела
//заполнение матрицы
int c1 = klinear*kwide*kheight*p; //число единиц
int k1 = 0;
int ofs_w, ofs_l, ofs_h;
srand (time(NULL));
while (k1<c1) {
ofs_w = rand()%kwide;
ofs_l = rand()%klinear;
ofs_h = rand()%kheight;
if (matrix[ofs_l][ofs_w][ofs_h]!=0) continue;
matrix[ofs_l][ofs_w][ofs_h] = 1;
k1++;
}

Приложение:
#include <iostream>
#include <fstream>
#include <time.h>
#include <Windows.h>

using namespace std;

char sip[255];
#define PRINT(x) {CharToOem(x,sip); cout << sip;}

void FindZPercolation(bool ifFind, int x, int y, int z);
void FindXPercolation(bool ifFind, int x, int y, int z);
void FindYPercolation(bool ifFind, int x, int y, int z);

DWORD WINAPI Thread_0(PVOID pvParam);
DWORD WINAPI Thread_1(PVOID pvParam);
DWORD WINAPI Thread_2(PVOID pvParam);

int wide, height, linear; // ширина, высота, длина
bool sh = 0, d = 0, v = 0;
bool ***matrix;
HANDLE Thread[3];

int main()
{
ofstream fout("output.txt");

do {PRINT("Введите длину: "); cin >> linear;} while (linear <= 0 || linear > 1000);
do {PRINT("Введите ширину: "); cin >> wide;} while (wide <= 0 || wide > 1000);
do {PRINT("Введите высоту: "); cin >> height;} while (height <= 0 || height > 1000);

// создаю matrix размерностью [wide][linear][height]
matrix = new bool**[wide];

for (int i = 0; i < wide; i++)
matrix[i] = new bool*[linear];

for (int i = 0; i < wide; i++)
for (int j = 0; j < linear; j++)
matrix[i][j] = new bool[height];

int s; // счетчик прогонов для каждой вероятности
int x, y, z, all, od; // количество перколяций
float px, py, pz, pall, pod; // вероятности возникновения перколяций

srand(time(0));
// заполняем матрицу значениями в соответствии с вероятностью
// перебираем вероятности
for (double p = 0.01; p <= 1; p+=0.01)
{
x = 0; y = 0; z = 0; all = 0; od = 0;

fout << "Вероятность - " << p << endl;


// Кол-во прогонов для всех вероятностей - 2.
for (s = 0; s < 10; s++)
{
sh = 0, d = 0, v = 0;

// Для каждого случая заполняем матрицу разными булевыми значениями
for (int i = 0; i < wide; i++)

for (int j = 0; j < linear; j++)
for (int k = 0; k < height; k++)
{

// число random принадлежит диапозону [0; 1]
double random = (double) rand() / RAND_MAX;
if (random <= p) matrix[i][j][k] = 1; else matrix[i][j][k] = 0;
}

// ищем путь от одной стены до другой

Thread[0] = CreateThread(NULL, 100000000, Thread_0, NULL, 0, NULL);
Thread[1] = CreateThread(NULL, 100000000, Thread_1, NULL, 0, NULL);
Thread[2] = CreateThread(NULL, 100000000, Thread_2, NULL, 0, NULL);

WaitForMultipleObjects(3, Thread, TRUE, INFINITE);
CloseHandle(Thread[0]);
CloseHandle(Thread[1]);
CloseHandle(Thread[2]);

// sh, v, d - результат выполнения функции нахождения перколяции
if (sh) x++;
if (d) y++;
if (v) z++;

if (sh && d && v) all++; // все перколяции
if (sh || d || v) od++; // хотя бы одна

fout << "Ширина: " << (sh ? "да" : "нет");
fout << "\nДлина: " << (d ? "да" : "нет");
fout << "\nВысота: " << (v ? "да" : "нет") << endl << endl;
}

fout << "Кол-во перколяций по ширине: " << x;
fout << "\nКол-во перколяций по длине: " << y;
fout << "\nКол-во перколяций по высоте: " << z;
fout << "\nКол-во всех перколяций: " << all;
fout << "\nХотя бы одна перколяция: " << od << endl;

px = (float) x/s;
py = (float) y/s;
pz = (float) z/s;
pall = (float) all/s;
pod = (float) od/s;

fout << "Вероятность возникновения перколяции по ширине: " << px;
fout << "\nВероятность возникновения перколяции по длине: " << py;
fout << "\nВероятность возникновения перколяции по высоте: " << pz;
fout << "\nВероятность возникновения всех перколяций " << pall;
fout << "\nВероятность возникновения хотя бы одной перколяции " << pod << endl << endl;
fout << "-------------------------------------------------------------" << endl;
}

// удаляю matrix размерностью [wide][linear][height]
for (int i = 0; i < wide; i++)
for (int j = 0; j < linear; j++)
delete [] matrix[i][j];

for (int i = 0; i < wide; i++)
delete [] matrix[i];

delete [] matrix;

fout.close();

return 0;
}

DWORD WINAPI Thread_0(PVOID pvParam)
{
bool Find = 0;
FindZPercolation(Find, 1, 1, 0);
return 0;
}

DWORD WINAPI Thread_1(PVOID pvParam)
{
bool Find = 0;
FindXPercolation(Find, 0, 1, 1);
return 0;
}

DWORD WINAPI Thread_2(PVOID pvParam)
{
bool Find = 0;
FindYPercolation(Find, 1, 0, 1);
return 0;
}

void FindZPercolation(bool ifFind, int x, int y, int z)
{
// Алгоритм обхода графа в ширину
// параметры функции: ifFind - найден или нет очередной протекающий элемент,
// x, y, z - текущие координаты, из которых нужно начать поиск

for (int i = x; i < wide-1; i++)
for (int j = y; j < linear-1; j++)
{
if (matrix[i][j][z]) // если ячейка протекает, то смотрим вниз, вправо и ещё в 1м
{ // направлении
if (matrix[i+1][j][z]) FindZPercolation(TRUE, i+1, j, z);

// вариант if (matrix[i-1][j][z]) не рассматриваем, т.к. его уже прошли
if (matrix[i][j+1][z]) FindZPercolation(TRUE, i, j+1, z);

if (z == height-1)
{
// если достигли конца z, тогда останавливаем все рекурсии
if (matrix[i][j][z] && ifFind) v = TRUE;

ExitThread(0);
}

if (matrix[i][j][z+1]) FindZPercolation(TRUE, i, j, z+1);
}
}
}

void FindYPercolation(bool ifFind, int x, int y, int z)
{
// Алгоритм обхода графа в ширину
// параметры функции: ifFind - найден или нет очередной протекающий элемент,
// x, y, z - текущие координаты, из которых нужно начать поиск

for (int i = x; i < wide-1; i++)
for (int j = z; j < height-1; j++)
{
if (matrix[i][y][j]) // если ячейка протекает, то смотрим вниз, вправо и ещё в 1м
{ // направлении, мысленно перевернув фигуру
if (matrix[i+1][y][j]) FindYPercolation(TRUE, i+1, y, j);

if (matrix[i][y][j+1]) FindYPercolation(TRUE, i, y, j+1);

if (y == linear-1)
{
// если достигли конца y, тогда останавливаем все рекурсии
if (matrix[i][y][j] && ifFind) d = TRUE;

ExitThread(0);
}

if (matrix[i][y+1][j]) FindYPercolation(TRUE, i, y+1, j);
}
}
}

void FindXPercolation(bool ifFind, int x, int y, int z)
{
// Алгоритм обхода графа в ширину
// параметры функции: ifFind - найден или нет очередной протекающий элемент,
// x, y, z - текущие координаты, из которых нужно начать поиск

for (int i = z; i < height-1; i++)
for (int j = y; j < linear-1; j++)
{
if (matrix[x][j][i]) // если ячейка протекает, то смотрим вниз, вправо и ещё в 1м
{ // направлении, мысленно перевернув фигуру
if (matrix[x][j+1][i]) FindXPercolation(TRUE, x, j+1, i);

if (matrix[x][j][i+1]) FindXPercolation(TRUE, x, j, i+1);

if (x == wide-1)
{
// если достигли конца x, тогда останавливаем все рекурсии
if (matrix[x][j][i] && ifFind) sh = TRUE;

ExitThread(0);
}

if (matrix[x+1][j][i]) FindXPercolation(TRUE, x+1, j, i);
}
}
}

Обсуждение

Неизвестный
12.12.2010, 22:38
общий
Очень рассчитываю на вашу помощь.
Неизвестный
13.12.2010, 12:59
общий
Я думаю проблема в самом алгоритме, а не в заполнении. Программа делает много лишней работы.
Вы можете привести исходное задание?
Неизвестный
13.12.2010, 16:24
общий
Задача: поиск порога перколяции в кубической решетке. То есть имеется решетка кубическая, она рандомно заполняется единичками в зависимости от вероятности заполнения( от 1 до 99% и для каждой вероятности несколько прогонов). Затем осуществляется протекание, то есть поиск пути по 3 направлениям - по горизонтали, по вертикали и по диагонали( то есть вглубь как бы). Нужно проверить можно ли от одной стороны дойти до противоположной и какова вероятность возникновения перколяции при данном заполнении решетки. В идеале первая перколяция должна появляться при 31% заполнения решетки. Но программа и это считает не точно...
Неизвестный
14.12.2010, 09:57
общий
Алгоритм неверный, так как проверяется не полный путь от грани до грани решётки, а только связь между каждой парой соседних слоёв. Поэтому и первая перколяция появляется значительно раньше 31%.
По хорошему надо всё переделать, но если результат Вас устраивает, то можно оптимизировать текущий алгоритм. Для этого необходимо удалить первые два рекурсивных вызова в каждой функции поиска, для примера ниже выделены удаляемые строки в FindZPercolation, аналогично нужно сделать в FindXPercolation и FindYPercolation:
Код:

void FindZPercolation(bool ifFind, int x, int y, int z)
{
for (int i = x; i < wide-1; i++)
for (int j = y; j < linear-1; j++)
{
if (matrix[i][j][z])
{
if (matrix[i+1][j][z]) FindZPercolation(TRUE, i+1, j, z);
if (matrix[i][j+1][z]) FindZPercolation(TRUE, i, j+1, z);
if (z == height-1)
{
if (matrix[i][j][z] && ifFind) v = TRUE;
ExitThread(0);
}
if (matrix[i][j][z+1]) FindZPercolation(TRUE, i, j, z+1);
}
}
}

После этого будет получаться тот же самый неправильный ответ, но значительно быстрее
Неизвестный
14.12.2010, 10:58
общий
Тогда лучше все переделать. Только уже не знаю как. Поэтому прошу у вас помощи.
Есть алгоритм для поиска перколяции на квадратной решетке(алгоритм хошена-копельмана). Вот там все правильно, т к там все решетка промаркировывается и и гораздо легче определить есть ли перколяция или нет. Но как его довести до кубической решетки - не знаю, т к очень плохо представляю как это все выглядит и что с чем сравнивать.
Перколяция на квадратной решетке.
Код:
#include <stdafx.h>
#include <time.h>
#include <conio.h>
#include <iostream>
#include <assert.h>
#include <stdlib.h>

using namespace std;


class UnionFind
{
public:
UnionFind( int max_labels );
~UnionFind();

int find( int x );
int Union( int x, int y );
int make_set();

int getNumLabels() const { return m_nLabels; }


protected:
int* labels;
int m_nLabels; // длина массива
};

// конструктор устанавливает структуры данных, необходимые находка объединение реализацией.
UnionFind::UnionFind( int max_labels )
{
m_nLabels = max_labels;
labels = new int[m_nLabels];
labels[0] = 0;
}

// Деструктор освобождает память
UnionFind::~UnionFind()
{
m_nLabels = 0;
delete labels;
labels = 0;
}


int UnionFind::find(int x)
{
int y = x;
while (labels[y] != y)
y = labels[y];

while (labels[x] != x) {
int z = labels[x];
labels[x] = y;
x = z;
}
return y;
}

int UnionFind::Union(int x, int y)
{
return labels[find(x)] = find(y);
}

// make_set creates новый эквивалентный класс и возвращение его метки
int UnionFind::make_set()
{
labels[0] ++;
labels[labels[0]] = labels[0];
return labels[0];
}

// End Union-Find implementation
// -------------------------------------------------------------------


class Matrix
{
public:
Matrix( int nRows, int nCols, double p );
~Matrix();

int hoshen_kopelman();
void check_labelling();
void perk (bool &v, bool &g);

// Оператор ввода
friend istream& operator>>( istream& stream, Matrix& m );
// Оператор вывода
friend ostream& operator<<( ostream& stream, const Matrix& m );

protected:
int m_nRows, m_nCols;
int** matrix;
double probability;
int total_clusters;
bool vert;
bool goriz;
};


Matrix::Matrix( int nRows, int nCols, double p ) :
m_nRows( nRows ), m_nCols( nCols ), probability (p)
{
matrix = (int **)calloc( nRows, sizeof(int*) ); // Функция calloc захватывает пространство для хранения массива
// из n элементов, каждый длиной size байт. Каждый элемент инициализируется в 0

for( int i=0; i < nRows; i++ ) {
matrix[i] = (int *)calloc( nCols, sizeof(int) );
memset (matrix[i], 0, nCols*sizeof(int));
}

//заполнение матрицы
int c1 = nRows*nCols*p; //число единиц
int k1 = 0;
int ofs_r, ofs_c;
srand (time(NULL));
while (k1<c1) {
ofs_r = rand()%nRows;
ofs_c = rand()%nCols;
if (matrix[ofs_r][ofs_c]!=0) continue;
matrix[ofs_r][ofs_c] = 1;
k1++;
}
//--------------------
}

Matrix::~Matrix()
{
for( int i=0; i < m_nRows; i++ )
free( matrix[i] ); // освобождаем блок памяти
free( matrix );
}

istream& operator>>( istream& stream, Matrix& m )
{
for( int i=0; i < m.m_nRows; i++ )
for( int j=0; j < m.m_nCols; j++ )
stream >> m.matrix[i][j];

return stream;
}


ostream& operator<<( ostream& stream, const Matrix& m )
{
for( int i=0; i < m.m_nRows; i++ ) {
for( int j=0; j < m.m_nCols; j++ ) {
stream.width(3);
stream << m.matrix[i][j];
}
stream << endl;
}
return stream;
}

#define max(a,b) (a>b?a:b)
#define min(a,b) (a>b?b:a)

// Label the clusters in "matrix". возвращает кол-во найденных кластеров.
int Matrix::hoshen_kopelman()
{
UnionFind uf( m_nRows*m_nCols/2 );

// просмотр матрицы
for( int i=0; i<m_nRows; i++ )
for (int j=0; j<m_nCols; j++)
if( matrix[i][j] ) { // если занято...
int up = (i==0 ? 0 : matrix[i-1][j]); // смотрим вверх
int left = (j==0 ? 0 : matrix[i][j-1]); // смотрим влево
switch (!!up + !!left) {
case 0:
matrix[i][j] = uf.make_set(); // новый кластер
break;

case 1: // часть существующего кластера
matrix[i][j] = max(up,left); // какой бы ни является отличным от нуля, помечен
break;

case 2: // связываем 2 кластера
matrix[i][j] = uf.Union(up, left);
break;
}
}

// примените перемаркирование к матрице


int* new_labels = new int[uf.getNumLabels()]; // распределите массив, инициализированный, чтобы обнулить
memset( new_labels, 0, sizeof(int)*uf.getNumLabels() );

for(int i=0; i < m_nRows; i++)
for (int j=0; j < m_nCols; j++)
if (matrix[i][j]) {
int x = uf.find(matrix[i][j]);
if (new_labels[x] == 0) {
new_labels[0]++;
new_labels[x] = new_labels[0];
}
matrix[i][j] = new_labels[x];
}

total_clusters = new_labels[0];

delete new_labels;
return total_clusters;
}


void Matrix::perk (bool &v, bool &g)
{
vert = false;
goriz = false;
for (int i=1; i<=total_clusters; i++) {
int mi; int mj = 0;
bool f1 = false, f2 = false; //проверка на горизонтальную
for (int mi=0; mi<m_nRows; mi++) { //просмотр первого и последнего столбца
if (matrix[mi][0]==i) f1 = true;
if (matrix[mi][m_nCols-1]==i) f2 = true;
}
if (f1 && f2) goriz = true;

f1 = false, f2 = false; //проверка на вертикальную
for (int mj=0; mj<m_nCols; mj++) { //просмотр первой и последней строки
if (matrix[0][mj]==i) f1 = true;
if (matrix[m_nRows-1][0]==i) f2 = true;
}
if (f1 && f2) vert = true;
if (vert && goriz) break;
}
v = vert; g = goriz;
}

int main()
{
int m, n;
int s; // счетчик прогонов для каждой вероятности
int v1,g1, ob, od; // количество перколяций
bool v, g;
float pv1,pg1,pob1,pod1; // вероятности возникновения перколяций

FILE *fp;


cout<<"Vvedite kol-vo strok and colon"<<endl;
cin >> m >> n; // m = строки, n = стобцы
if ((fp=freopen("percol.txt", "w", stdout)) == NULL)
{
printf("He удается открыть файл.\n");
exit(1);
}
for (double p = 0.01; p<=1; p+=0.01) { //перебираем вероятности
//if (p>0.99) p=1;
s=0; v1=0; g1=0; ob=0; od=0;
for (int k=0;k<10; k++){

Matrix matrix( m, n, p );
// вывод вероятности
cout<<"probability - "<< p<< endl;

// вывод матрицы
// cout << " --input-- \n" << matrix;

// поиск кластеров
int clusters = matrix.hoshen_kopelman();

// вывод результатов
//cout << " --output-- \n" << matrix;


matrix.perk (v, g);
if(v==true) v1+=1;
if(g==true) g1+=1;
if((v==true)&&(g==true)) ob+=1; // обе перколяции
if((v==true)||(g==true)) od+=1; // хотя бы одна
cout << "Vertical: " << (v?"yes":"no") <<";\nGorizontal: " << (g?"yes":"no") << endl<<endl;

s+=1;
}
cout<<"kol-vo vertical perkolyaciy "<< v1<<";\nKol-vo gorizontal perkolyaciy " <<g1<<";\nKol-vo obeih perkolyaciy "<<ob<<";\nHotya by odna perkolyaciya "<<od<<endl;
cout<< "kol-vo progonov dlya veroyatnosti "<<p<<" - "<<s<<endl<<endl;
pv1=(float)v1/s;
pg1=(float)g1/s;
pob1=(float)ob/s;
pod1=(float)od/s;
cout<<"Veroyatnost' vozniknoveniya vertical perkolyacii "<<pv1<<";\nVeroyatnost' vozniknoveniya gorizontal perkolyacii "<<pg1<<";\nVeroyatnost' vozniknoveniya obeih perkolyaciy "<<pob1<<";\nVeroyatnost' vozniknoveniya hotyaby odnoj perkolyacii "<<pod1<<endl<<endl;

cout<<"-------------------------------------------------------------"<<endl;
}



fclose(fp);
getch();
return 0;
}
Неизвестный
14.12.2010, 11:31
общий
Если я правильно понял задание и Ваш код, то ошибки 2:
1 Не все варианты проверяются, так что она может не найти путь там, где он есть
2 Выполняется перебор без минимальной оптимизации. На графах такое не проходит. Время обработки растет со скоростью факториала.

Я на С++ не очень люблю программировать и времени мало. Набросал на C#, но так, чтобы было почти как в С++. Языки похожи, функции можно копировать почти без изменения. Посмотрите, похож ли этот код на нужныйМеня смущает, что он на большом промежутке 10-100 всегда выдает очень похожие результаты в районе 67-69.

Главное отличие: используется поиск в длину (он здесь лучше работает) и помечаются посещенные узлы. Если мы уже были в этом узле, он полностью будет обработан и заново его исследовать не нужно. Ваша же программа должна проходить их снова и снова. Поскольку, у нас 3 поиска, я использую 3 метки. Паралельно такой код запускать нельзя, но можно скопировать матрицу 3 раза. Правда, большого прироста скорости ожидать от этого не стоит.
Неизвестный
14.12.2010, 11:32
общий
Код:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace txt2xml
{
class Percolation
{
static byte[][][] Matrix;
static int X, Y, Z;

public static void Main()
{
Console.WriteLine("Введите длину (X): ");
while (!int.TryParse(Console.ReadLine(), out X)) ;
Console.WriteLine("Введите высоту (Y): ");
while (!int.TryParse(Console.ReadLine(), out Y)) ;
Console.WriteLine("Введите глубину (Z): ");
while (!int.TryParse(Console.ReadLine(), out Z)) ;

Matrix = new byte[Z][][]; //Создаем матрицу
for (int z = 0; z < Z; z++)
{
Matrix[z] = new byte[Y][];
for (int y = 0; y < Y; y++)
Matrix[z][y] = new byte[X];
}

Random Rand=new Random();

int cntAll = 0, cntSome = 0, cntX = 0, cntY = 0, cntZ = 0;

for (double Prob = 0.01; Prob <= 1.0; Prob += 0.01)
{
Console.WriteLine("Вероятность: {0}", Prob);

for (int s = 0; s < 10; s++)
{
for (int z = 0; z < Z; z++)
for (int y = 0; y < Y; y++)
for (int x = 0; x < X; x++)
Matrix[z][y][x] = (byte)(Rand.NextDouble() <= Prob ? 1 : 0);
}

bool HaveZ = FindZPercolation();
bool HaveY = FindYPercolation();
bool HaveX = FindXPercolation();

if (HaveX) cntX++;
if (HaveY) cntY++;
if (HaveZ) cntZ++;
if (HaveX && HaveY && HaveZ) cntAll++;
if (HaveX || HaveY || HaveZ) cntSome++;

Console.WriteLine("X: {0}\nY: {1}\nZ: {2}", HaveX ? "да" : "нет", HaveY ? "да" : "нет", HaveZ ? "да" : "нет");
}

Console.WriteLine("Статистика");
Console.WriteLine("Кол-во перколяций по ширине: {0}", cntX);
Console.WriteLine("\nКол-во перколяций по длине: {0}", cntY);
Console.WriteLine("\nКол-во перколяций по высоте: {0}", cntZ);
Console.WriteLine("\nКол-во всех перколяций: {0}", cntAll);
Console.WriteLine("\nХотя бы одна перколяция: {0}", cntSome);
}

private static bool FindZPercolation()
{
const int Flag = 4;
for (int y = 0; y < Y; y++)
for (int x = 0; x < X; x++)
{
int E = Matrix[0][y][x];
if (E != 0 && E != Flag)
if (TraverseZ(0, y, x))
return true;
}
return false;
}

private static bool FindYPercolation()
{
const int Flag = 3;
for (int z = 0; z < Z; z++)
for (int x = 0; x < X; x++)
{
int E = Matrix[z][0][x];
if (E != 0 && E != Flag)
if (TraverseY(z, 0, x))
return true;
}
return false;
}


private static bool FindXPercolation()
{
const int Flag = 2;
for (int z = 0; z < Z; z++)
for (int y = 0; y < Y; y++)
{
int E = Matrix[z][y][0];
if (E != 0 && E != Flag)
if (TraverseX(z, y, 0))
return true;
}
return false;
}

private static bool TraverseZ(int z, int y, int x)
{
const int Flag = 4;
Matrix[z][y][x] = Flag;

if (z == Z - 1) return true;
else
{
byte E=Matrix[z + 1][y][x];
if (E != 0 && E != Flag)
if (TraverseZ(z + 1, y, x))
return true;
}

if (y < Y - 1)
{
byte E = Matrix[z][y + 1][x];
if (E != 0 && E != Flag)
if (TraverseZ(z, y + 1, x))
return true;
}

if (x < X - 1)
{
byte E = Matrix[z][y][x + 1];
if (E != 0 && E != Flag)
if (TraverseZ(z, y, x + 1))
return true;
}

if (x > 0)
{
byte E = Matrix[z][y][x - 1];
if (E != 0 && E != Flag)
if (TraverseZ(z, y, x - 1))
return true;
}

if (y > 0)
{
byte E = Matrix[z][y - 1][x];
if (E != 0 && E != Flag)
if (TraverseZ(z, y - 1, x))
return true;
}

if (z > 0)
{
byte E = Matrix[z - 1][y][x];
if (E != 0 && E != Flag)
if (TraverseZ(z - 1, y, x))
return true;
}

return false;
}

private static bool TraverseY(int z, int y, int x)
{
const int Flag = 3;
Matrix[z][y][x] = Flag;

if (y == Y - 1) return true;
else
{
byte E = Matrix[z][y + 1][x];
if (E != 0 && E != Flag)
if (TraverseY(z, y + 1, x))
return true;
}

if (z < Z - 1)
{
byte E = Matrix[z + 1][y][x];
if (E != 0 && E != Flag)
if (TraverseY(z + 1, y, x))
return true;
}

if (x < X - 1)
{
byte E = Matrix[z][y][x + 1];
if (E != 0 && E != Flag)
if (TraverseY(z, y, x + 1))
return true;
}

if (x > 0)
{
byte E = Matrix[z][y][x - 1];
if (E != 0 && E != Flag)
if (TraverseY(z, y, x - 1))
return true;
}

if (z > 0)
{
byte E = Matrix[z - 1][y][x];
if (E != 0 && E != Flag)
if (TraverseY(z - 1, y, x))
return true;
}

if (y > 0)
{
byte E = Matrix[z][y - 1][x];
if (E != 0 && E != Flag)
if (TraverseY(z, y - 1, x))
return true;
}

return false;
}

private static bool TraverseX(int z, int y, int x)
{
const int Flag = 2;
Matrix[z][y][x] = Flag;

if (x == X - 1) return true;
else
{
byte E = Matrix[z][y][x + 1];
if (E != 0 && E != Flag)
if (TraverseX(z, y, x + 1))
return true;
}

if (y < Y - 1)
{
byte E = Matrix[z][y + 1][x];
if (E != 0 && E != Flag)
if (TraverseX(z, y + 1, x))
return true;
}

if (z < Z - 1)
{
byte E = Matrix[z + 1][y][x];
if (E != 0 && E != Flag)
if (TraverseX(z + 1, y, x))
return true;
}

if (x > 0)
{
byte E = Matrix[z][y][x - 1];
if (E != 0 && E != Flag)
if (TraverseX(z, y, x - 1))
return true;
}

if (y > 0)
{
byte E = Matrix[z][y - 1][x];
if (E != 0 && E != Flag)
if (TraverseX(z, y - 1, x))
return true;
}

if (z > 0)
{
byte E = Matrix[z - 1][y][x];
if (E != 0 && E != Flag)
if (TraverseX(z - 1, y, x))
return true;
}

return false;
}
}
}
Неизвестный
14.12.2010, 13:04
общий
Цитата: 268417
Меня смущает, что он на большом промежутке 10-100 всегда выдает очень похожие результаты в районе 67-69.

Если решетка от 10 до 100, то перколяция появляется при 67-69% заполнения решетки ? Я правильно вас поняла?
Правильный код будет как на квадратной решетке, который я выше привела( который с маркировкой). Но т к как его переделать под кубическую я не понимаю, то пошла считать другими путями, а их правильность уже определяется по полученному результату=) А правильный результат как я уже сказала при 31% должна появляться перколяция. Конечно, на маленькой решетки это число может быть чуть меньше, но около того. Поэтому если ваш код выдает такой результат, то программа работает правильно=) Сейчас сама проверить не могу, тк в C# совсем не разбираюсь.
Неизвестный
14.12.2010, 13:38
общий
Вот такой у меня вывод:

Кол-во перколяций по ширине: 67
Кол-во перколяций по длине: 68
Кол-во перколяций по высоте: 66
Кол-во всех перколяций: 65
Хотя бы одна перколяция: 70

Вероятности я не сделал. Вроде, они просто 1/10 от этих данных. Кстати, 31% - это для квадрата или куба? Вполне может быть, что для квадрата один расчетный результат, а для куба - другой.

А код можно скопировать в свой (все функции кроме Main). Убрав пару лишних ключевых слов, они превратится в функции С++. На ковыряния кода в С++ у меня сейчас времени нет. Работа :)
Неизвестный
14.12.2010, 17:22
общий
Для квадрата порог 54-56. А для куба 31.
Количество перколяций тут не столько важно, как вероятность при которой появляется первая перколяция. Поэтому и надо смотреть от 1 до 99% заполнения. Сама задача поэтому и называется поиск порога перколяции на кубической решетке.
Неизвестный
14.12.2010, 23:22
общий
Вот переделала алгоритм на квадратной решетке на кубическую. Переделала - громко сказано, добавила лишь третью переменную. А самые важный функции поиска, маркировки не работают.

Код:
//#include <stdafx.h>
#include <time.h>
#include <conio.h>
#include <iostream>
#include <assert.h>
#include <stdlib.h>

using namespace std;


class UnionFind
{
public:
UnionFind( int max_labels );
~UnionFind();

int find( int x );
int Union( int x, int y, int z );
int make_set();

int getNumLabels() const { return m_nLabels; }


protected:
int** labels;
int m_nLabels; // длина массива
};

// конструктор устанавливает структуры данных, необходимые находка объединение реализацией.
UnionFind::UnionFind( int max_labels )
{
m_nLabels = max_labels;
labels = new int[m_nLabels];
labels[0][0] = 0;
}

// Деструктор освобождает память
UnionFind::~UnionFind()
{
m_nLabels = 0;
delete labels;
labels = 0;
}


int UnionFind::find(int x)
{
int y = x;
while (labels[y] != y)
y = labels[y];

while (labels[x] != x) {
int z = labels[x];
labels[x] = y;
x = z;
}
return y;
}

int UnionFind::Union(int x, int y, int z)
{
return labels[find(x)] = find(y);
}

// make_set creates новый эквивалентный класс и возвращение его метки
int UnionFind::make_set()
{
labels[0][0] ++;
labels[labels[0][0]] = labels[0][0];
return labels[0][0];
}

// End Union-Find implementation
// -------------------------------------------------------------------


class Matrix
{
public:
Matrix( int nRows, int nCols, int nWide, double p );
~Matrix();

int hoshen_kopelman();
void check_labelling();
void perk (bool &v, bool &g, bool &d);

// Оператор ввода
friend istream& operator>>( istream& stream, Matrix& m );
// Оператор вывода
friend ostream& operator<<( ostream& stream, const Matrix& m );

protected:
int m_nRows, m_nCols, m_nWide;
int*** matrix;
double probability;
int total_clusters;
bool vert;
bool goriz;
bool diag;
};


Matrix::Matrix( int nRows, int nCols, int nWide, double p ) :
m_nRows( nRows ), m_nCols( nCols ), m_nWide( nWide), probability (p)
{
matrix = (int ***)calloc( nRows, sizeof(int**) ); // Функция calloc захватывает пространство для хранения массива
// из n элементов, каждый длиной size байт. Каждый элемент инициализируется в 0

for( int i=0; i < nRows; i++ )
matrix[i] = (int **)calloc( nCols, sizeof(int*) );

for (int i = 0; i < nRows; i++)
for (int j = 0; j < nCols; j++) {
matrix[i][j] = (int *)calloc(nWide, sizeof(int) );
memset (matrix[i][j], 0, nWide*sizeof(int));
}



//заполнение матрицы
int c1 = nRows*nCols*nWide*p; //число единиц
int k1 = 0;
int ofs_r, ofs_c, ofs_w;
srand (time(NULL));
while (k1<c1) {
ofs_r = rand()%nRows;
ofs_c = rand()%nCols;
ofs_w = rand()%nWide;
if (matrix[ofs_r][ofs_c][ofs_w]!=0) continue;
matrix[ofs_r][ofs_c][ofs_w] = 1;
k1++;
}
//--------------------
}

Matrix::~Matrix()
{
/*for( int i=0; i < m_nRows; i++ )
free( matrix[i] ); // освобождаем блок памяти
free( matrix );
*/
for (int i = 0; i < m_nRows; i++)
for (int j = 0; j < m_nCols; j++)
delete [] matrix[i][j];

for (int i = 0; i < m_nRows; i++)
delete [] matrix[i];

delete [] matrix;
}

istream& operator>>( istream& stream, Matrix& m )
{
for( int i=0; i < m.m_nRows; i++ )
for( int j=0; j < m.m_nCols; j++ )
for( int k=0; k < m.m_nWide; k++ )
stream >> m.matrix[i][j][k];

return stream;
}


ostream& operator<<( ostream& stream, const Matrix& m )
{
for( int i=0; i < m.m_nRows; i++ ) {
for( int j=0; j < m.m_nCols; j++ )
for( int k=0; k < m.m_nWide; k++ )
{
stream.width(3);
stream << m.matrix[i][j][k];
}
stream << endl;
}
return stream;
}

#define max(a,b) (a>b?a:b)
#define min(a,b) (a>b?b:a)

// Label the clusters in "matrix". возвращает кол-во найденных кластеров.
int Matrix::hoshen_kopelman()
{
UnionFind uf( m_nRows*m_nCols*m_nCols/2 );

// просмотр матрицы
for( int i=0; i<m_nRows; i++ )
for (int j=0; j<m_nCols; j++)
for( int k=0; j < m_nWide; k++ )
if( matrix[i][j][k] ) { // если занято...
int up = (i==0 ? 0 : matrix[i-1][j][k]); // смотрим вверх
int left = (j==0 ? 0 : matrix[i][j-1][k]);// смотрим влево
int vgl = (k==0 ? 0 : matrix[i][j][k-1]);
switch (!!up + !!left) {
case 0:
matrix[i][j][k] = uf.make_set(); // новый кластер
break;

case 1: // часть существующего кластера
matrix[i][j][k] = max(up,left, vgl); // какой бы ни является отличным от нуля, помечен
break;

case 2: // связываем 2 кластера
matrix[i][j][k] = uf.Union(up, left,vgl);
break;
}
}

// примените перемаркирование к матрице


int* new_labels = new int[uf.getNumLabels()]; // распределите массив, инициализированный, чтобы обнулить
memset( new_labels, 0, sizeof(int)*uf.getNumLabels() );

for(int i=0; i < m_nRows; i++)
for (int j=0; j < m_nCols; j++)
for( int k=0; k < m_nWide; k++ )
if (matrix[i][j][k]) {
int x = uf.find(matrix[i][j][k]);
if (new_labels[x] == 0) {
new_labels[0]++;
new_labels[x] = new_labels[0];
}
matrix[i][j][k] = new_labels[x];
}

total_clusters = new_labels[0];

delete new_labels;
return total_clusters;
}


void Matrix::perk (bool &v, bool &g, bool &d)
{
vert = false;
goriz = false;
diag = false;
for (int i=1; i<=total_clusters; i++) {
int mi = 0; int mj = 0; int mk = 0;
bool f1 = false, f2 = false; //проверка на горизонтальную
for (int mk=0; mk<m_nWide; mk++)
for (int mi=0; mi<m_nRows; mi++) { //просмотр первого и последнего столбца
if (matrix[mi][0][mk]==i) f1 = true;
if (matrix[mi][m_nCols-1][mk]==i) f2 = true;
}
if (f1 && f2) goriz = true;

f1 = false, f2 = false; //проверка на вертикальную
for (int mk=0; mk<m_nWide; mk++)
for (int mj=0; mj<m_nCols; mj++) { //просмотр первой и последней строки
if (matrix[0][mj][0]==i) f1 = true;
if (matrix[m_nRows-1][0][mk]==i) f2 = true;
}
if (f1 && f2) vert = true;

f1 = false, f2 = false; //проверка на диагональную
for (int mk=0; mk<m_nWide; mk++) { //просмотр первой и последней строки
if (matrix[0][0][mk]==i) f1 = true;
if (matrix[m_nRows-1][0][m_nWide]==i) f2 = true;
}
if (f1 && f2) diag = true;

if (vert && goriz && diag) break;
}
v = vert; g = goriz; d = diag;
}

int main()
{
int m, n, l;
int s; // счетчик прогонов для каждой вероятности
int v1,g1, d1, ob, od; // количество перколяций
bool v, g, d;
float pv1,pg1,pd1, pob1,pod1; // вероятности возникновения перколяций

FILE *fp;


cout<<"Vvedite dlinu, shirinu and vysota "<<endl;
cin >> m >> n >>l ; // m = строки, n = стобцы
if ((fp=freopen("output.txt", "w", stdout)) == NULL)
{
printf("He удается открыть файл.\n");
exit(1);
}
for (double p = 0.01; p<=1; p+=0.01) { //перебираем вероятности
//if (p>0.99) p=1;
s=0; v1=0; g1=0; d1=0; ob=0; od=0;
for (int k=0;k<10; k++){

Matrix matrix( m, n, l, p );
// вывод вероятности
cout<<"probability - "<< p<< endl;

// вывод матрицы
// cout << " --input-- \n" << matrix;

// поиск кластеров
int clusters = matrix.hoshen_kopelman();

// вывод результатов
//cout << " --output-- \n" << matrix;


matrix.perk (v, g, d);
if(v==true) v1+=1;
if(g==true) g1+=1;
if(d==true) d1+=1;
if((v==true)&&(g==true)&&(d==true)) ob+=1; // обе перколяции
if((v==true)||(g==true)||(d==true)) od+=1; // хотя бы одна
cout << "Vertical: " << (v?"yes":"no") <<";\nGorizontal: " << (g?"yes":"no") << endl<<endl;

s+=1;
}
cout<<"kol-vo vertical perkolyaciy "<< v1<<";\nKol-vo gorizontal perkolyaciy " <<g1<<";\nKol-vo diagonal perkolyaciy "<<d1<<";\nKol-vo obeih perkolyaciy "<<ob<<";\nHotya by odna perkolyaciya "<<od<<endl;
cout<< "kol-vo progonov dlya veroyatnosti "<<p<<" - "<<s<<endl<<endl;
pv1=(float)v1/s;
pg1=(float)g1/s;
pd1=(float)d1/s;
pob1=(float)ob/s;
pod1=(float)od/s;
cout<<"Veroyatnost' vozniknoveniya vertical perkolyacii "<<pv1<<";\nVeroyatnost' vozniknoveniya gorizontal perkolyacii "<<pg1<<";\nVeroyatnost' vozniknoveniya diagonal perkolyacii "<<pd1<<";\nVeroyatnost' vozniknoveniya obeih perkolyaciy "<<pob1<<";\nVeroyatnost' vozniknoveniya hotyaby odnoj perkolyacii "<<pod1<<endl<<endl;

cout<<"-------------------------------------------------------------"<<endl;
}



fclose(fp);
getch();
return 0;
}
Неизвестный
15.12.2010, 11:52
общий
Вчера сообщение так и не отправилось. Так вероятность - это p из цикла? Тогда все правильно. Оно как раз где-то на этом уровне и переключается с "нет" на "да".

Код:
Вероятность: 0,29
X: нет
Y: нет
Z: нет
Вероятность: 0,3
X: нет
Y: нет
Z: да
Вероятность: 0,31
X: да
Y: нет
Z: да
Вероятность: 0,32
X: да
Y: да
Z: нет
Вероятность: 0,33
X: да
Y: да
Z: да


Так что просто из моего кода возьмите 6 функций и вставьте в свою программу. Мультитридинг из Вашей программы можно убирать. Здесь общие данные меняются - оно так работать не будет. Программа получится гораздо проще, чем была.

У меня координаты в кубе стоят в "нормальном" порядке [z][y][x]. Если у Вас наоборот, их надо просто переставить местами. Из глобальных переменных используется только тот же Matrix и X,Y,Z вместо wide, height, linear (так гораздо понятнее, какая переменная к чему относится.
Неизвестный
15.12.2010, 13:05
общий
Да, p -это вероятность


Вроде все сделала, но то ли где то ошиблась, то ли что то еще надо изменить - программа не находит перколяцию при любой вероятности.


Код:


#include "stdafx.h"

#include <time.h>
#include <conio.h>
#include <iostream>
#include <assert.h>
#include <stdlib.h>

using namespace std;
int X, Y, Z;
int ***Matrix;
bool FindXPercolation();
bool FindYPercolation();
bool FindZPercolation();

bool TraverseX(int x, int y, int z);
bool TraverseY(int x, int y, int z);
bool TraverseZ(int x, int y, int z);

int main()
{
int X, Y, Z;
int cntAll = 0, cntSome = 0, cntX = 0, cntY = 0, cntZ = 0; // количество перколяций
float pv1,pg1,pd1, pob1,pod1; // вероятности возникновения перколяций
int ***Matrix;

FILE *fp;


cout<<"Vvedite dlinu, vysotu and glubinu "<<endl;
cin >> X >> Y >>Z ; // m = строки, n = стобцы
if ((fp=freopen("output.txt", "w", stdout)) == NULL)
{
printf("He удается открыть файл.\n");
exit(1);
}
// создаю matrix размерностью [X][Y][Z]
Matrix = new int**[X];

for (int i = 0; i < X; i++)
Matrix[i] = new int*[Y];

for (int i = 0; i < X; i++)
for (int j = 0; j < Y; j++)
Matrix[i][j] = new int[Z];



for (double p = 0.01; p <= 1.0; p += 0.01)
{
int k=0; int cntAll = 0, cntSome = 0, cntX = 0, cntY = 0, cntZ = 0;
// вывод вероятности
cout<<"вероятность - "<< p<< endl;
// счетчик прогонов
for (int s = 0; s < 10; s++)

{
for (int x = 0; x < X; x++)
for (int y = 0; y < Y; y++)
for (int z = 0; z < Z; z++)
{
double random = (double) rand() / RAND_MAX;
if (random <= p) Matrix[x][y][z] = 1; else Matrix[x][y][z] = 0;
}


bool HaveX = FindXPercolation();
bool HaveY = FindYPercolation();
bool HaveZ = FindZPercolation();

if (HaveX) cntX++;
if (HaveY) cntY++;
if (HaveZ) cntZ++;
if (HaveX && HaveY && HaveZ) cntAll++;
if (HaveX || HaveY || HaveZ) cntSome++;

cout << "по ширине " << (HaveX?"yes":"no") <<";\nпо длине: " << (HaveY?"yes":"no") <<";\nпо высоте: " << (HaveZ?"yes":"no") << endl<<endl;
k+=1;
}


cout<<"Кол-во перколяций по ширине: "<< cntX<<";\nКол-во перколяций по длине: " <<cntY<<";\nКол-во перколяций по высоте: "<<cntZ<<";\nКол-во всех перколяций: "<<cntAll<<";\nХотя бы одна перколяция: "<<cntSome<<endl;
cout<< "kol-vo progonov dlya veroyatnosti "<<p<<" - "<<k<<endl<<endl;
pv1=(float)cntX/k;
pg1=(float)cntY/k;
pd1=(float)cntZ/k;
pob1=(float)cntAll/k;
pod1=(float)cntSome/k;
cout<<"Вероятность возникновения перколяции по ширине "<<pv1<<";\nВероятность возникновения перколяции по длине "<<pg1<<";\nVВероятность возникновения перколяции по высоте "<<pd1<<";\nВероятность возникновения всех перколяций "<<pob1<<";\nВероятность возникновения хотя бы одной "<<pod1<<endl<<endl;

cout<<"-------------------------------------------------------------"<<endl;
}
fclose(fp);
getch();
return 0;
}



bool FindXPercolation()
{
const int Flag = 4;
for (int y = 0; y < Y; y++)
for (int z = 0; z < Z; z++)
{
int E = Matrix[0][y][z];
if (E != 0 && E != Flag)
if (TraverseX(0, y, z))
return true;
}
return false;
}

bool FindYPercolation()
{
const int Flag = 3;
for (int x = 0; x < X; x++)
for (int z = 0; z < Z; z++)
{
int E = Matrix[x][0][Z];
if (E != 0 && E != Flag)
if (TraverseY(x, 0, z))
return true;
}
return false;
}


bool FindZPercolation()
{
const int Flag = 2;
for (int x = 0; x < X; x++)
for (int y = 0; y < Y; y++)
{
int E = Matrix[x][y][0];
if (E != 0 && E != Flag)
if (TraverseX(x, y, 0))
return true;
}
return false;
}

bool TraverseX(int x, int y, int z)
{
const int Flag = 4;
Matrix[x][y][y] = Flag;

if (x == X - 1) return true;
else
{
int E = Matrix[x + 1][y][z];
if (E != 0 && E != Flag)
if (TraverseX(x + 1, y, z))
return true;
}

if (y < Y - 1)
{
int E = Matrix[x][y + 1][z];
if (E != 0 && E != Flag)
if (TraverseX(x, y + 1, z))
return true;
}

if (z < Z - 1)
{
int E = Matrix[x][y][z + 1];
if (E != 0 && E != Flag)
if (TraverseX(x, y, z + 1))
return true;
}

if (z > 0)
{
int E = Matrix[x][y][z - 1];
if (E != 0 && E != Flag)
if (TraverseX(x, y, z - 1))
return true;
}

if (y > 0)
{
int E = Matrix[x][y - 1][z];
if (E != 0 && E != Flag)
if (TraverseX(x, y - 1, z))
return true;
}

if (x > 0)
{
int E = Matrix[x - 1][y][z];
if (E != 0 && E != Flag)
if (TraverseX(x - 1, y, z))
return true;
}

return false;
}

bool TraverseY(int x, int y, int z)
{
const int Flag = 3;
Matrix[x][y][z] = Flag;

if (y == Y - 1) return true;
else
{
int E = Matrix[x][y + 1][z];
if (E != 0 && E != Flag)
if (TraverseY(x, y + 1, z))
return true;
}

if (x < X - 1)
{
int E = Matrix[x + 1][y][z];
if (E != 0 && E != Flag)
if (TraverseY(x + 1, y, x))
return true;
}

if (z < Z - 1)
{
int E = Matrix[x][y][z + 1];
if (E != 0 && E != Flag)
if (TraverseY(x, y, z + 1))
return true;
}

if (z > 0)
{
int E = Matrix[x][y][z - 1];
if (E != 0 && E != Flag)
if (TraverseY(x, y, z - 1))
return true;
}

if (x > 0)
{
int E = Matrix[x - 1][y][z];
if (E != 0 && E != Flag)
if (TraverseY(x - 1, y, z))
return true;
}

if (y > 0)
{
int E = Matrix[x][y - 1][z];
if (E != 0 && E != Flag)
if (TraverseY(x, y - 1, z))
return true;
}

return false;
}

bool TraverseZ(int x, int y, int z)
{
const int Flag = 2;
Matrix[x][y][z] = Flag;

if (z == Z - 1) return true;
else
{
int E = Matrix[x][y][z + 1];
if (E != 0 && E != Flag)
if (TraverseZ(x, y, z + 1))
return true;
}

if (y < Y - 1)
{
int E = Matrix[x][y + 1][z];
if (E != 0 && E != Flag)
if (TraverseZ(x, y + 1, z))
return true;
}

if (x < X - 1)
{
int E = Matrix[x + 1][y][z];
if (E != 0 && E != Flag)
if (TraverseZ(x + 1, y, z))
return true;
}

if (z > 0)
{
int E = Matrix[x][y][z - 1];
if (E != 0 && E != Flag)
if (TraverseZ(x, y, z - 1))
return true;
}

if (y > 0)
{
int E = Matrix[x][y - 1][z];
if (E != 0 && E != Flag)
if (TraverseZ(x, y - 1, z))
return true;
}

if (x > 0)
{
int E = Matrix[x - 1][y][z];
if (E != 0 && E != Flag)
if (TraverseZ(x - 1, y, z))
return true;
}

return false;
}
Неизвестный
15.12.2010, 22:47
общий
Ошибки было 2:
1 Вы совершенно напрасно определили переменные глобально и в функции MainВ результате, созданная матрица существовала только внутри этой функции, а остальные видели неинициализированные переменные.
2 При замене что-то отломалось и поиск зацикливался. Программа обрывалась с переполнением стека. Место ошибки я искать не стал, а просто опять скопировал свои функции в код.

Сейчас работает, но почему-то медленнее, чем на C#. Если такой код уже пойдет, я могу его завтра ответом оформить.

Код:

#include "stdafx.h"
#include <time.h>
#include <conio.h>
#include <iostream>
#include <assert.h>
#include <stdlib.h>
using namespace std;

int X, Y, Z;
int ***Matrix;

bool FindXPercolation();
bool FindYPercolation();
bool FindZPercolation();
bool TraverseX(int x, int y, int z);
bool TraverseY(int x, int y, int z);
bool TraverseZ(int x, int y, int z);

int main()
{
int cntAll = 0, cntSome = 0, cntX = 0, cntY = 0, cntZ = 0; // количество перколяций
float pv1,pg1,pd1, pob1,pod1; // вероятности возникновения перколяций

FILE *fp;
cout<<"Vvedite dlinu, vysotu and glubinu "<<endl; cin >> X >> Y >>Z ; // m = строки, n = стобцы
if ((fp=freopen("output.txt", "w", stdout)) == NULL)
{
printf("He удается открыть файл.\n");
exit(1);
}
// создаю matrix размерностью [X][Y][Z]
Matrix = new int**[X];
for (int i = 0; i < X; i++)
Matrix[i] = new int*[Y];
for (int i = 0; i < X; i++)
for (int j = 0; j < Y; j++)
Matrix[i][j] = new int[Z];
for (double p = 0.01; p <= 1.0; p += 0.01)
{
int k=0;
int cntAll = 0, cntSome = 0, cntX = 0, cntY = 0, cntZ = 0;
// вывод вероятности
cout<<"вероятность - "<< p<< endl;
// счетчик прогонов
for (int s = 0; s < 10; s++)
{
for (int x = 0; x < X; x++)
for (int y = 0; y < Y; y++)
for (int z = 0; z < Z; z++)
{
double random = (double) rand() / RAND_MAX;
if (random <= p) Matrix[x][y][z] = 1; else Matrix[x][y][z] = 0;
}
bool HaveX = FindXPercolation();
bool HaveY = FindYPercolation();
bool HaveZ = FindZPercolation();

if (HaveX) cntX++;
if (HaveY) cntY++;
if (HaveZ) cntZ++;
if (HaveX && HaveY && HaveZ) cntAll++;
if (HaveX || HaveY || HaveZ) cntSome++;
cout << "по ширине " << (HaveX?"yes":"no") <<";\nпо длине: " << (HaveY?"yes":"no") <<";\nпо высоте: " << (HaveZ?"yes":"no") << endl<<endl;
k+=1;
}
cout<<"Кол-во перколяций по ширине: "<< cntX<<";\nКол-во перколяций по длине: " <<cntY<<";\nКол-во перколяций по высоте: "<<cntZ<<";\nКол-во всех перколяций: "<<cntAll<<";\nХотя бы одна перколяция: "<<cntSome<<endl;
cout<< "kol-vo progonov dlya veroyatnosti "<<p<<" - "<<k<<endl<<endl;
pv1=(float)cntX/k;
pg1=(float)cntY/k;
pd1=(float)cntZ/k;
pob1=(float)cntAll/k;
pod1=(float)cntSome/k;
cout<<"Вероятность возникновения перколяции по ширине "<<pv1<<";\nВероятность возникновения перколяции по длине "<<pg1<<";\nVВероятность возникновения перколяции по высоте "<<pd1<<";\nВероятность возникновения всех перколяций "<<pob1<<";\nВероятность возникновения хотя бы одной "<<pod1<<endl<<endl;
cout<<"-------------------------------------------------------------"<<endl;
}
fclose(fp);
getch();
return 0;
}

bool FindZPercolation()
{
const int Flag = 4;
for (int y = 0; y < Y; y++)
for (int x = 0; x < X; x++)
{
int E = Matrix[0][y][x];
if (E != 0 && E != Flag)
if (TraverseZ(0, y, x))
return true;
}
return false;
}

bool FindYPercolation()
{
const int Flag = 3;
for (int z = 0; z < Z; z++)
for (int x = 0; x < X; x++)
{
int E = Matrix[z][0][x];
if (E != 0 && E != Flag)
if (TraverseY(z, 0, x))
return true;
}
return false;
}


bool FindXPercolation()
{
const int Flag = 2;
for (int z = 0; z < Z; z++)
for (int y = 0; y < Y; y++)
{
int E = Matrix[z][y][0];
if (E != 0 && E != Flag)
if (TraverseX(z, y, 0))
return true;
}
return false;
}

bool TraverseZ(int z, int y, int x)
{
const int Flag = 4;
Matrix[z][y][x] = Flag;

if (z == Z - 1) return true;
else
{
int E=Matrix[z + 1][y][x];
if (E != 0 && E != Flag)
if (TraverseZ(z + 1, y, x))
return true;
}

if (y < Y - 1)
{
int E = Matrix[z][y + 1][x];
if (E != 0 && E != Flag)
if (TraverseZ(z, y + 1, x))
return true;
}

if (x < X - 1)
{
int E = Matrix[z][y][x + 1];
if (E != 0 && E != Flag)
if (TraverseZ(z, y, x + 1))
return true;
}

if (x > 0)
{
int E = Matrix[z][y][x - 1];
if (E != 0 && E != Flag)
if (TraverseZ(z, y, x - 1))
return true;
}

if (y > 0)
{
int E = Matrix[z][y - 1][x];
if (E != 0 && E != Flag)
if (TraverseZ(z, y - 1, x))
return true;
}

if (z > 0)
{
int E = Matrix[z - 1][y][x];
if (E != 0 && E != Flag)
if (TraverseZ(z - 1, y, x))
return true;
}

return false;
}

bool TraverseY(int z, int y, int x)
{
const int Flag = 3;
Matrix[z][y][x] = Flag;

if (y == Y - 1) return true;
else
{
int E = Matrix[z][y + 1][x];
if (E != 0 && E != Flag)
if (TraverseY(z, y + 1, x))
return true;
}

if (z < Z - 1)
{
int E = Matrix[z + 1][y][x];
if (E != 0 && E != Flag)
if (TraverseY(z + 1, y, x))
return true;
}

if (x < X - 1)
{
int E = Matrix[z][y][x + 1];
if (E != 0 && E != Flag)
if (TraverseY(z, y, x + 1))
return true;
}

if (x > 0)
{
int E = Matrix[z][y][x - 1];
if (E != 0 && E != Flag)
if (TraverseY(z, y, x - 1))
return true;
}

if (z > 0)
{
int E = Matrix[z - 1][y][x];
if (E != 0 && E != Flag)
if (TraverseY(z - 1, y, x))
return true;
}

if (y > 0)
{
int E = Matrix[z][y - 1][x];
if (E != 0 && E != Flag)
if (TraverseY(z, y - 1, x))
return true;
}

return false;
}

bool TraverseX(int z, int y, int x)
{
const int Flag = 2;
Matrix[z][y][x] = Flag;

if (x == X - 1) return true;
else
{
int E = Matrix[z][y][x + 1];
if (E != 0 && E != Flag)
if (TraverseX(z, y, x + 1))
return true;
}

if (y < Y - 1)
{
int E = Matrix[z][y + 1][x];
if (E != 0 && E != Flag)
if (TraverseX(z, y + 1, x))
return true;
}

if (z < Z - 1)
{
int E = Matrix[z + 1][y][x];
if (E != 0 && E != Flag)
if (TraverseX(z + 1, y, x))
return true;
}

if (x > 0)
{
int E = Matrix[z][y][x - 1];
if (E != 0 && E != Flag)
if (TraverseX(z, y, x - 1))
return true;
}

if (y > 0)
{
int E = Matrix[z][y - 1][x];
if (E != 0 && E != Flag)
if (TraverseX(z, y - 1, x))
return true;
}

if (z > 0)
{
int E = Matrix[z - 1][y][x];
if (E != 0 && E != Flag)
if (TraverseX(z - 1, y, x))
return true;
}

return false;
}
Неизвестный
15.12.2010, 23:00
общий
А вы для какой решетке считал перколяцию? почему то для решетке 100х100х100 он прерывается - bool TraverseZ(int z, int y, int x) { . также стек переполняется.
Да, можете оформлять ответом, считает правильно, но для маленьких решеток( Большое спасибо.
И в кратце можете объяснить саму суть вашего алгоритма? И для чего используется переменная flag.
Неизвестный
17.12.2010, 04:09
общий
Программа на C# считала до 250. На С++ даже 80 не берет. Просто стек слишком короткий.
Суть проста. Он обходит начальную плоскость (x=0, y=0 или z=0) и если находит непомеченный пробитый элемент (1), начинает с него поиск в глубину. Ищет до любого элемента на противоположном конце (x=X-1, y=Y-1 или z=Z-1). Для этого он проверяет соседей текущего элемента и если находит свободный - переходит туда рекурсивно. Каждый посещенный элемент помечается флагом, чтобы еще раз его не пришлось проверять. Если зайдет в тупик, рекурсия позволяет ему откатиться на шаг назад и продолжить с другими соседями. Раз нам нужно проверить 3 раза один куб, то нужно 3 метки. Я обхожусь одной переменной. Просто поиск X ставит метку 2, а следующие - большее число, поэтому для них поле не помечено. Иначе мне перед каждым поиском пришлось бы заново обходить все поле и сбрасывать все метки.
Здесь вообще самое длительное развлечение - это заполнение куба. Поиск становится долгим только в районе 0,31. На низких и высоких вероятностях поиск завершается очень быстро.

Flag - Метка текущего поиска. Она пишется в куб вместо 1 и означает, что эта клетка уже исследована.
bool FindYPercolation() - обходит свою плоскость и запускает поиск из пробитых элементов
bool TraverseY(int z, int y, int x) - сам поиск в глубину. Пытается рекурсивно сделать шаг в каждом направлении.
Неизвестный
17.12.2010, 04:35
общий
это ответ
Здравствуйте, Yulesik!

Раз та программа уже полностью рабочая, я сделал более сложную. Она уже зависит только от доступной памяти. Проверил на кубе 500*500*500 - работает, хоть и очень долго. Максимальный путь на таком кубе составил 42311 шагов. В стандартный стек столько функций не помещается. Оптимизации:

Куб хранится одним блоком памяти. Так он меньше места занимает и доступ быстрее.
Эмуляция рекурсии стеком. В структуре State хранится информация, которая хранилась бы в экземпляре функции. Теперь переполнения стека не будет.
Стек кешируется, чтобы объекты не создавались-удалялись постоянно. На это уходит очень много времени.

Теперь размер 200*200*200 берет очень резво, только на переходных вероятностях затормаживается.

Приложение:
#include "stdafx.h"
#include <time.h>
#include <conio.h>
#include <iostream>
#include <assert.h>
#include <stdlib.h>

using namespace std;

const char FlagX=2, FlagY=3, FlagZ=4;

struct State // структура для хранения рекурсивного стека
{
State(int x, int y, int z, char *pos, State *prev) : x(x),y(y),z(z),Prev(prev),Pos(pos) {Stage=0;}
int x, y, z;
int Stage;
char *Pos;
State *Prev;
};

int X, Y, Z;//длины размерностей
int yStep, zStep;//Шаг в байтах между элементами этой размерности

char *Matrix;

//Обслуживание создания/удаления элементов стека
State *WaitList = NULL;

inline State *newState(int x, int y, int z, char *pos, State* prev)
{
if(!WaitList)
return new State(x,y,z,pos,prev);
else
{
State *S=WaitList;
WaitList=WaitList->Prev;
S->x=x; S->y=y; S->z=z;
S->Pos=pos; S->Prev=prev;
S->Stage=0;
return S;
}
}

inline void deleteState(State *S)
{
S->Prev=WaitList;
WaitList=S;
}

#define Del(S) while(S){ State *T=S; S=S->Prev; deleteState(T);}



//сама программа

bool FindXPercolation();
bool FindYPercolation();
bool FindZPercolation();

int main()
{
setlocale( LC_ALL,"Russian" );
int cntAll = 0, cntSome = 0, cntX = 0, cntY = 0, cntZ = 0; // количество перколяций
float pv1,pg1,pd1, pob1,pod1; // вероятности возникновения перколяций
cout<<"Vvedite dlinu, vysotu and glubinu "<<endl;
cin >> X >> Y >>Z ; // m = строки, n = стобцы
yStep = X;
zStep = X*Y;
// создаю matrix размерностью [X][Y][Z]
int size = X*Y*Z;
Matrix = new char[size];
if(!Matrix)
{
cout <<"Слишком большие размеры!";
return 1;
}

srand( (unsigned)time( NULL ) );
int randstep = RAND_MAX / 100;
for (int p = randstep; p <= randstep*100; p += randstep) {
int k=0;
int cntAll = 0, cntSome = 0, cntX = 0, cntY = 0, cntZ = 0; // вывод вероятности
cout<<"вероятность - "<< p/randstep*0.01 << endl;
// счетчик прогонов

for (int s = 0; s < 10; s++)
{
char *b = Matrix;
for (int i = 0; i<size; i++) //Заполняем матрицу
*(b++) = (rand() <= p ) ? 1 : 0;

bool HaveX = FindXPercolation();
cout << "X " << (HaveX ? "да":"нет");
bool HaveY = FindYPercolation();
cout << "\tY " << (HaveY ? "да":"нет");
bool HaveZ = FindZPercolation();
cout << "\tZ " << (HaveZ ? "да":"нет") << endl;
if (HaveX) cntX++;
if (HaveY) cntY++;
if (HaveZ) cntZ++;

if (HaveX && HaveY && HaveZ) cntAll++;
if (HaveX || HaveY || HaveZ) cntSome++;
k++;
}
cout<<"Кол-во перколяций по ширине: "<< cntX<<";\nКол-во перколяций по длине: " <<cntY<<";\nКол-во перколяций по высоте: "<<cntZ<<";\nКол-во всех перколяций: "<<cntAll<<";\nХотя бы одна перколяция: "<<cntSome<<endl;
cout<< "kol-vo progonov dlya veroyatnosti " << p/randstep*0.01 <<" - "<<k<<endl<<endl;
pv1=(float)cntX/k;
pg1=(float)cntY/k;
pd1=(float)cntZ/k;
pob1=(float)cntAll/k;
pod1=(float)cntSome/k;
cout<<"Вероятность возникновения перколяции по ширине "<<pv1<<";\nВероятность возникновения перколяции по длине "<<pg1<<";\nVВероятность возникновения перколяции по высоте "<<pd1<<";\nВероятность возникновения всех перколяций "<<pob1<<";\nВероятность возникновения хотя бы одной "<<pod1<<endl<<endl;
cout<<"-------------------------------------------------------------"<<endl;
}

int st=0;
while(WaitList)
{
State *S=WaitList;
WaitList=WaitList->Prev;
delete S;
st++;
}

cout << "Максимальный путь: " << st << endl;

getch();
return 0;
}

//Эти функции пытаются сделать шаг в соответствующем направлении
inline State* Zup(State *S, char Flag)
{
if(S->z < Z-1)
{
char *t=S->Pos+zStep;
if(*t!=0 && *t!=Flag)
S = newState(S->x, S->y, S->z+1, t, S);
}
return S;
}

inline State* Zdown(State *S, char Flag)
{
if(S->z > 0)
{
char *t=S->Pos-zStep;
if(*t!=0 && *t!=Flag)
S = newState(S->x, S->y, S->z-1, t, S);
}
return S;
}

inline State* Yup(State *S, char Flag)
{
if(S->y < Y-1)
{
char *t=S->Pos+yStep;
if(*t!=0 && *t!=Flag)
S = newState(S->x, S->y+1, S->z, t, S);
}
return S;
}

inline State* Ydown(State *S, char Flag)
{
if(S->y > 0)
{
char *t=S->Pos-yStep;
if(*t!=0 && *t!=Flag)
S = newState(S->x, S->y-1, S->z, t, S);
}
return S;
}

inline State* Xup(State *S, char Flag)
{
if(S->x < X-1)
{
char *t=S->Pos+1;
if(*t!=0 && *t!=Flag)
S = newState(S->x+1, S->y, S->z, t, S);
}
return S;
}

inline State* Xdown(State *S, char Flag)
{
if(S->x > 0)
{
char *t=S->Pos-1;
if(*t!=0 && *t!=Flag)
S = newState(S->x-1, S->y, S->z, t, S);
}
return S;
}

//Эти функции перебирают возможные шаги (сам поиск)
bool TravZ(int x, int y, int z, char *pos)
{
State *S = newState(x,y,z,pos,0);
char Flag = FlagZ;
while(S!=0)
{
switch(S->Stage)
{
case 0://Вход в функцию
if(S->z == Z - 1) { Del(S); return true;}
*(S->Pos) = Flag;
case 1:
S->Stage=2;
S = Zup(S, Flag);
break;
case 2:
S->Stage=3;
S = Yup(S, Flag);
break;
case 3:
S->Stage=4;
S = Xup(S, Flag);
break;
case 4:
S->Stage=5;
S = Xdown(S, Flag);
break;
case 5:
S->Stage=6;
S = Ydown(S, Flag);
break;
case 6:
S->Stage=7;
S = Zdown(S, Flag);
break;
case 7://ячейка обработана
State *t=S;
S=S->Prev;
deleteState(t);
}
}
return false;
}

bool TravY(int x, int y, int z, char *pos)
{
State *S = newState(x,y,z,pos,0);
char Flag = FlagY;
while(S!=0)
{
switch(S->Stage)
{
case 0://Вход в функцию
if(S->y == Y - 1) { Del(S); return true;}
*(S->Pos) = Flag;
case 1:
S->Stage=2;
S = Yup(S, Flag);
break;
case 2:
S->Stage=3;
S = Zup(S, Flag);
break;
case 3:
S->Stage=4;
S = Xup(S, Flag);
break;
case 4:
S->Stage=5;
S = Xdown(S, Flag);
break;
case 5:
S->Stage=6;
S = Zdown(S, Flag);
break;
case 6:
S->Stage=7;
S = Ydown(S, Flag);
break;
case 7://ячейка обработана
State *t=S;
S=S->Prev;
deleteState(t);
}
}
return false;
}

bool TravX(int x, int y, int z, char *pos)
{
State *S = newState(x,y,z,pos,0);
char Flag = FlagX;
while(S!=0)
{
switch(S->Stage)
{
case 0://Вход в функцию
if(S->x == X - 1) { Del(S); return true;}
*(S->Pos) = Flag;
case 1:
S->Stage=2;
S = Xup(S, Flag);
break;
case 2:
S->Stage=3;
S = Yup(S, Flag);
break;
case 3:
S->Stage=4;
S = Zup(S, Flag);
break;
case 4:
S->Stage=5;
S = Zdown(S, Flag);
break;
case 5:
S->Stage=6;
S = Ydown(S, Flag);
break;
case 6:
S->Stage=7;
S = Xdown(S, Flag);
break;
case 7://ячейка обработана
State *t=S;
S=S->Prev;
deleteState(t);
}
}
return false;
}

//Эти функции обходят плоскость и запускают поиск из найденых узлов
bool FindZPercolation() //Z=0
{
char *b = Matrix;
for(int y=0; y<Y; y++)
for(int x=0; x<X; x++)
{
if(*b!=0 && *b!=FlagZ)
if(TravZ(x, y, 0, b))
return true;
b++;
}
return false;
}

bool FindYPercolation() //Y=0
{
char *b;
for(int z=0; z<Z; z++)
{
b = Matrix + z*zStep;
for(int x=0; x<X; x++)
{
if(*b!=0 && *b!=FlagY)
if(TravY(x, 0, z, b))
return true;
b++;
}
}
return false;
}

bool FindXPercolation() //Y=0
{
char *b;
for(int z=0; z<Z; z++)
{
b = Matrix + z*zStep;
for(int y=0; y<Y; y++)
{
if(*b!=0 && *b!=FlagX)
if(TravX(0, y, z, b))
return true;
b += yStep;
}
}
return false;
}
Форма ответа