Форум программистов, компьютерный форум CyberForum.ru

Поиск минимального остовного дерева на графе - C++

Восстановить пароль Регистрация
 
 
Рейтинг: Рейтинг темы: голосов - 20, средняя оценка - 4.70
frEEze00
2 / 2 / 1
Регистрация: 10.07.2014
Сообщений: 25
10.08.2014, 15:22     Поиск минимального остовного дерева на графе #1
Переделал программу найденную в интернете, написал через функцию.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#include <iostream>;
#include <fstream>;
 
 
using namespace std;
 
void creatFile(int maxCost, int kolVer, int **cost){
    //функция, создающая текстовый файл с заданным названием и записывающая в него данные для хранения
    int i,j;
    char name[50];
    cout<<"Введите название файла:";
    cin >> name;
    strcat(name, ".txt");
    ofstream out(name);
    out<<maxCost<<"\n"; //Записываем в первую строку файла максимальный вес ребра
    out<<kolVer<<"\n";  //Записываем во вторую строку количество вершин
 
    //в следующии строки записываем матрицу смежности
for (i=1; i<=kolVer; i++)
{   
    for (j=1; j<=kolVer; j++)
    {   
        out<<cost[i][j]<<" ";
    }
    out<<"\n";
}
 
    out.close();
    cout<<"Файл создан\n";
};
void poiskMinOstDer(int maxCost, int kolVer, int **cost)
{       //Функциия поиска минимального оставного дерева на графе
    int min=maxCost;
    int minCost=0;
    int i,i2,i3,j,j2,j3,n,shet=1,iRebra=0;
    bool used[99]={false};
    used[1]=true;
    int rebro[99]={0};
    
    while (shet<kolVer)
    {
        for (i=1; i<=kolVer; i++)
        {
            for (j=1; j<=kolVer; j++)
            {
                if (cost[i][j]<min) 
                {
                    if (used[i]!=false)
                    {
                        min=cost[i][j];
                        i2=i3=i;
                        j2=j3=j;
                    }
                        if (used[j3]==false || used[j3]==false)
                        {
                            rebro[iRebra]=j2;
                            iRebra++;
                            shet++;
                            minCost=minCost+min;
                            used[j2]=true;
                        }
                    cost[i2][j2]=cost[j2][i2]=maxCost;
                }
            }
        }
    }
    cout<<1<<" --> ";
    for (i=0; i<kolVer-1; i++)
    {
        cout<<rebro[iRebra];
        if (i<kolVer-2){cout<<" --> ";}
    }
    cout<<"\n Минимальная стоимость: "<<minCost;
};
int main(){
setlocale (LC_ALL, "RUS");
int i,j;
int maxCost=100; //Максимальный вес ребра
int kolVer; //Количество вершин графа
int **cost;
cost = new int *[40];
for (i=0; i<40; i++){cost[i]=new int[40];}
 
 
cout<<"Введите максимальный вес ребра:\n";
cin>>maxCost;
cout<<"Введите количесто вершин графа:\n";
cin>>kolVer;
 
// Записываем в cost вес ребер с помощью матрицы смежности
cout<<"Введите матрицу смежности:\n";
for (i=1; i<=kolVer; i++)
{
    for (j=1; j<=kolVer; j++)
    {
        cin>>cost[i][j];
        if (cost[i][j]==0)
        {cost[i][j]=maxCost;}
    }
}
 
creatFile(maxCost,kolVer,cost);
poiskMinOstDer(maxCost, kolVer, cost);
 
 
system("pause");
return 0;
};
При вводе значений например
Макс вес ребра: 5
Кол-во вершин: 2
матрица смежности:
0 1
1 0
И любое название файла, выводит:
Файл создан.
1 --> 0(все верное, кроме этого нуля)
Мин стоимость: 1

при вводе большего количества ребер или значения первого элемента не равным нулю, программа доходит до вывода надписи "Файл создан", а дальше останавливается... Не пойму в чем проблема...

Добавлено через 26 минут
Простите, остОвного дерева.

Добавлено через 2 часа 15 минут
убрал цикл while. Осталась проблема что после "1 --> ..." всегда выводятся нули.

Добавлено через 11 часов 25 минут
Немного изменил алгоритм функции, на

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
...
for (i=1; i<=kolVer; i++)
{
    for (j=1; j<=kolVer; j++)
    {
        if (cost[i][j]<min) 
        {
            if (used[i]==true)
            {
                min=cost[i][j];
                i2=i3=i;
                j2=j3=j;
            }
        }
        
        if (used[i3]==false || used[j3]==false)
        {
            rebro[iRebra]=j2;
            iRebra++;
            minCost=minCost+min;
            used[j2]=true;
        }
        cost[i2][j2]=cost[j2][i2]=maxCost;
        
    }
}
 
...
Теперь выскакивает ошибка "Unhandled exception at 0x008b10d8 in {НазваниеПроэкта}.exe: 0xC0000005: Access violation reading location 0x750aa5e5."

ругается на строчку
C++
1
    if (used[i3]==false || used[j3]==false)
а конкретнее мне кажется на переменную j2. Помогите пожалуйста, всю голову уже сломал.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
10.08.2014, 15:22     Поиск минимального остовного дерева на графе
Посмотрите здесь:

C++ поиск циклов в графе
Поиск на графе C++
C++ Поиск минимального элемента идеально сбалансированного дерева
Поиск остовного леса методом Соллина C++
Поиск циклов в графе. Поиск центра взвешенного графа C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
zss
Модератор
Эксперт С++
 Аватар для zss
5944 / 5549 / 1783
Регистрация: 18.12.2011
Сообщений: 14,171
Завершенные тесты: 1
10.08.2014, 15:31     Поиск минимального остовного дерева на графе #2
У Вас везде считается, что индексы массива в диапазоне [1:kolVer]
например:
Цитата Сообщение от frEEze00 Посмотреть сообщение
for (i=1; i<=kolVer; i++)
{
for (j=1; j<=kolVer; j++)
{
cin>>cost[i][j];....
А на самом деле индексы массива в диапазоне [0:kolVer-1].
frEEze00
2 / 2 / 1
Регистрация: 10.07.2014
Сообщений: 25
10.08.2014, 15:52  [ТС]     Поиск минимального остовного дерева на графе #3
zss, проблема не в этом, переделал все циклы на циклы вида:
C++
1
for (i=0; i<kolVer; i++)....
и так же сменил строку
C++
1
used[1]=true;
на
C++
1
used[0]=true;
, но
ошибка не исчезла.
вот код программы, которую я нашел в интернете и переделал, она работает :
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include "stdafx.h"
#include <conio.h>
#include <iostream>
using namespace std;
 
int _tmain(int argc, _TCHAR* argv[])
{
setlocale (LC_ALL,"RUS");
int a,b,u,v,n,i,j,ne=1;
int visited[10]={0},min,mincost=0,cost[10][10];
 
int path[100]={0}; //В этот массив будут записываться вершины, по которым составиться путь
int path_index=0;
 
 
cout<<"Введи количество вершин "; cin>>n;
cout<<"Введи матрицу смежности\n";
 
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
cin>>cost[i][j];
if(cost[i][j]==0)
cost[i][j]=999; //999 - это что-типа бесконечности. Должно быть больше чем значения веса каждого из ребер в графе
}
visited[1]=1;
cout<<"\n";
 
while(ne < n)
{
for(i=1,min=999;i<=n;i++)
for(j=1;j<=n;j++)
if(cost[i][j]< min)
if(visited[i]!=0)
{
min=cost[i][j];
a=u=i;
b=v=j;
}
if(visited[u]==0 || visited[v]==0)
{
path[path_index]=b;
path_index++;
//cout<<"\n "<<ne++<<" "<<a<<" "<<b<<min; //Можно вывести так
ne++; //если строчку выше раскомментировать - эту закомментировать
mincost+=min;
visited[b]=1;
 
}
cost[a][b]=cost[b][a]=999;
}
 
cout<<"\n";
 
cout<<1<<" —> ";
for (int i=0;i<n-1;i++)
{
cout<<path[i];
if (i<n-2) cout<<" —> ";
}
 
cout<<"\n Минимальная стоимость "<<mincost;
 
cin.get();
cin.get();
 
return 0;
}
ya_noob
_
200 / 144 / 9
Регистрация: 08.10.2011
Сообщений: 432
10.08.2014, 16:27     Поиск минимального остовного дерева на графе #4
Цитата Сообщение от frEEze00 Посмотреть сообщение
Переделал программу найденную в интернете
хреново переделали видать, т.к. в строке 50 (в первом посте) операция бессмысленна, min не должен здесь менять значение. скорее всего есть и другие ошибки переделки.
Цитата Сообщение от zss Посмотреть сообщение
У Вас везде считается, что индексы массива в диапазоне [1:kolVer]
...
А на самом деле индексы массива в диапазоне [0:kolVer-1].
А НА САМОМ ДЕЛЕ там всё правильно, в строках 92-100 (в первом посте) написано почему и менять индексы не нужно.
Цитата Сообщение от frEEze00 Посмотреть сообщение
вот код программы, которую я нашел в интернете и переделал, она работает
мечетесь, мечетесь от одного решения к другому. а как хоть этот метод поиска остовного дерева называется то? может вначале теорию почитать про поиск остовных деревьев и написать свое осмысленное решение, а не шариться по нету в поисках готового.
frEEze00
2 / 2 / 1
Регистрация: 10.07.2014
Сообщений: 25
10.08.2014, 17:34  [ТС]     Поиск минимального остовного дерева на графе #5
Цитата Сообщение от ya_noob Посмотреть сообщение
хреново переделали видать, т.к. в строке 50 (в первом посте) операция бессмысленна, min не должен здесь менять значение. скорее всего есть и другие ошибки переделки.
min должен менять значение, так как по другому ты не сможешь сравнивать элементы. и в исходной программе min меняет значение(строка 36).

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

Сейчас еще нашел ошибку у себя. вот переделанная фунуция:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
for (i=1; i<=kolVer; i++)
{
    for (j=1; j<=kolVer; j++)
    {
        if (cost[i][j]<min) 
        {
            if (used[i]!=false)
            {
            min=cost[i][j];
            i2=i3=i;
            j2=j3=j;
            }
        }
    }
 
    if (used[i3]==false || used[j3]==false)
    {
        rebro[iRebra]=j2;
        cout<<"\n rebro[i]="<<rebro[i]<<"\n";
        iRebra++;
        shet++;
        minCost=minCost+min;
        used[j2]=true;
    }
    cost[i2][j2]=cost[j2][i2]=maxCost;
 
}
остальное все так же как в первом посте..
Ошибка пропала, но теперь проблема в том, что переменная rebro[iRebra] выводиться всегда равная нулю. и minCost увеличивается на min только один раз. пример вывода:
99
3
8 7 6
5 4 3
2 1 0

выводит :
1 -> 0 -> 0
Мин стоимость: 6

а должен выводить:
1 -> 3 -> 2
Мин стоимость: 7

ps. В 19 строчке вывожу переменную rebro, выводит ноль. Почему то не присваивается ей значение j2; (ну или присваивается только один раз, когда j2 и есть равное 0)
ya_noob
_
200 / 144 / 9
Регистрация: 08.10.2011
Сообщений: 432
10.08.2014, 17:46     Поиск минимального остовного дерева на графе #6
Цитата Сообщение от frEEze00 Посмотреть сообщение
min должен менять значение, так как по другому ты не сможешь сравнивать элементы. и в исходной программе min меняет значение
ну если так, то что делает эта строка (сторка 46 из 1-го поста)
C++
1
if (cost[i][j]<min)
frEEze00
2 / 2 / 1
Регистрация: 10.07.2014
Сообщений: 25
10.08.2014, 18:02  [ТС]     Поиск минимального остовного дерева на графе #7
Цитата Сообщение от ya_noob Посмотреть сообщение
ну если так, то что делает эта строка (строка 46 из 1-го поста)

сравниваем элемент массива с минимальным(в первом случае минимальный у нас равен максимальному), если cost[i][j]<min, то проверяем переменную used на не ложь(в первом случае она правда), а далее как раз и присваиваем значение cost[i][j] переменной min.
ya_noob
_
200 / 144 / 9
Регистрация: 08.10.2011
Сообщений: 432
10.08.2014, 18:12     Поиск минимального остовного дерева на графе #8
Цитата Сообщение от frEEze00 Посмотреть сообщение
сравниваем элемент массива с минимальным(в первом случае минимальный у нас равен максимальному), если cost[i][j]<min, то проверяем переменную used на не ложь(в первом случае она правда), а далее как раз и присваиваем значение cost[i][j] переменной min.
всё фигня давай по новой.
перевести с языка программирования на русский я и сам могу. я просил написать в чем СМЫСЛ данной строки.
подсказки:
1. не элемент массива, а элемент матрицы
2. элемент матрицы - это элемент матрицы смежности, которой представлен граф
3. наводящий вопрос: когда мы пробегаемся по матрице смежности, что мы должны проверить в первую очередь?
frEEze00
2 / 2 / 1
Регистрация: 10.07.2014
Сообщений: 25
10.08.2014, 18:23  [ТС]     Поиск минимального остовного дерева на графе #9
Цитата Сообщение от ya_noob Посмотреть сообщение
не элемент массива, а элемент матрицы
Матрица - это двумерный массив, в моем случае динамический.

В которой каждая строка отвечает за определенную вершину.
например:
0 2 3 1
2 0 4 0
3 4 0 0
1 0 0 0

здесь вершина 1 связана со второй ребром размером 2, с третьей размером в три, с четвертой размером в 1.
вторая вершина с первой ребром размером 2, с третьей размером 4, с четвертой не связана..
и так далее...

а проверить мы должны в первую очередь, использовалась ли эта вершина ранее, если да, то игнорировать эту строку и столбец.
ya_noob
_
200 / 144 / 9
Регистрация: 08.10.2011
Сообщений: 432
10.08.2014, 18:29     Поиск минимального остовного дерева на графе #10
Цитата Сообщение от frEEze00 Посмотреть сообщение
Матрица - это двумерный массив
и всё же писать "матрица" уместнее, чем "массив", не возникает двусмысленности. ладно это всё семантика. а вот теперь по делу
Цитата Сообщение от frEEze00 Посмотреть сообщение
а проверить мы должны в первую очередь, использовалась ли эта вершина ранее
есть действие с матрицей, которое надо совершить еще раньше. что же это?
frEEze00
2 / 2 / 1
Регистрация: 10.07.2014
Сообщений: 25
10.08.2014, 18:37  [ТС]     Поиск минимального остовного дерева на графе #11
Цитата Сообщение от ya_noob Посмотреть сообщение
есть действие с матрицей, которое надо совершить еще раньше. что же это?
сдаюсь, и какое же?
ya_noob
_
200 / 144 / 9
Регистрация: 08.10.2011
Сообщений: 432
10.08.2014, 18:42     Поиск минимального остовного дерева на графе #12
Цитата Сообщение от frEEze00 Посмотреть сообщение
сдаюсь, и какое же?
эээх, так не интересно.
правильный ответ (пишу с сожалением):
а первым делом надо убедиться что есть ребро из вершины i в вершину j, что в программе и делается с помощью инструкции cost[i][j]<min, где в min лежит некоторое сигнальное значение, означающее, что нет ребра в ячейке. в строках 97-98 это четко написано.
теперь надеюсь ясно почему min нельзя менять
frEEze00
2 / 2 / 1
Регистрация: 10.07.2014
Сообщений: 25
10.08.2014, 18:56  [ТС]     Поиск минимального остовного дерева на графе #13
Цитата Сообщение от ya_noob Посмотреть сообщение
в строках 97-98 это четко написано.
да, при значение 0 следует то, что вершины не соединяются(или это одна и та же вершина). Мы заменяем этот ноль на максимальное значение для того, чтобы в последующем оно не участвовало в сравнение с min. А min, мне кажется, мы всё равно должны менять. по другому программа не будет работать. Вот например:
первая строка матрицы: 6 5 2 8
в начале функции мы min присвоили максимальное значение ребра, пусть 99.
далее мы сравниваем min c 6. Поскольку 99>6 мы присваиваем min=6;
далее сравниваем 6 с 5, присваиваем min значение 5.
далее аналогично 5 с 2, после чего min=2.
поскольку 8>2 то min так и остается равным 2.
Это означает что из первой вершины, у нас ближайший путь в вершину 3. И путь этот равен 2.

А вот дальше уже, мы снова должны присвоить min=maxCost. (чего кстати у меня нет, спасибо) и идти уже по третьей строке, игнорируя 1 столбец. и так же искать минимальное значение.
ya_noob
_
200 / 144 / 9
Регистрация: 08.10.2011
Сообщений: 432
10.08.2014, 19:09     Поиск минимального остовного дерева на графе #14
Цитата Сообщение от frEEze00 Посмотреть сообщение
А min, мне кажется, мы всё равно должны менять.
скорее всего в строке 46 вместо min должно стоять что-другое, строка 50 тоже смущает (без всякой причины меняется переменная min), в строке 54 тоже какая-то хрень (2 раза одно и то же) и тд и тп. в общем, какой-то подозрительный алгоритм.
frEEze00
2 / 2 / 1
Регистрация: 10.07.2014
Сообщений: 25
10.08.2014, 19:19  [ТС]     Поиск минимального остовного дерева на графе #15
Цитата Сообщение от ya_noob Посмотреть сообщение
в строке 46 вместо min должно стоять что-другое
все норм, так и должно быть min

Цитата Сообщение от ya_noob Посмотреть сообщение
строка 50 тоже смущает (без всякой причины меняется переменная min)
не без причины, про что я писал в прошлом посту, о том что идем по строчке, сравниваем и если надо меняем min.

Цитата Сообщение от ya_noob Посмотреть сообщение
в строке 54 тоже какая-то хрень (2 раза одно и то же)
это я уже поменял(не делайте упор на первый пост, я после выкладывал измененную функцию)

вот на чем я сейчас остановился:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
for (i=1; i<=kolVer; i++)
{   
    min=maxCost;
    for (j=1; j<=kolVer; j++)
    {
        if (cost[i][j]<min) 
        {
            if (used[i]!=false)
            {
            min=cost[i][j];
            i2=i3=i;
            j2=j3=j;
            }
        }
    }
    if (used[i3]==false || used[j3]==false)
    {
        rebro[iRebra]=j2;
        iRebra++;
        shet++;
        minCost=minCost+min;
        used[j2]=true;
    }
    cost[i2][j2]=cost[j2][i2]=maxCost;
 
}
 
cout<<1<<" —> ";
for (i=0; i<kolVer-1; i++)
{
cout<<rebro[iRebra];
if (i<kolVer-2){cout<<" —> ";}
}
cout<<"\n Минимальная стоимость: "<<minCost;
но опять же, выводит всегда 1 -> 0 -> 0 -> ... и так далее (проблема с переменной rebro[iRebra])
и выводит минимальную стоимость неверную...проблема с min или c minCost=minCost+min.

а возможно проблема с переменной used[], и тем за что она отвечает. Как я и писал выше, проверяем первую строку, переходим на другую(куда ближе) а далее игнорируем первую строку, used[] как раз за это и отвечает...
ya_noob
_
200 / 144 / 9
Регистрация: 08.10.2011
Сообщений: 432
10.08.2014, 19:30     Поиск минимального остовного дерева на графе #16
Цитата Сообщение от frEEze00 Посмотреть сообщение
все норм, так и должно быть min
осссссспади! опять двадцать пять. зачем мы целую страницу исписали то?
начинаем всё заново (по последней версии функции):
строка 6: мы договорились, что это проверка на наличие ребра i->j или как?
frEEze00
2 / 2 / 1
Регистрация: 10.07.2014
Сообщений: 25
10.08.2014, 19:38  [ТС]     Поиск минимального остовного дерева на графе #17
Цитата Сообщение от ya_noob Посмотреть сообщение
строка 6: мы договорились, что это проверка на наличие ребра i->j или как?
это то, о чем я писал. Сравнение элементов строки между собой, для поиска минимального.

а наличие ребра у меня проверяется до этого, это здесь не имеет значения.

C++
1
2
3
4
5
6
7
8
for (i=1; i<=kolVer; i++)
{
    for (j=1; j<=kolVer; j++)
    {
        cin>>cost[i][j];
        if (cost[i][j]==0){cost[i][j]=maxCost;}
    }
}
Когда ввожу матрицу, сразу заменяю нули на максимальное, чтобы потом не мешали в сравнение.
ya_noob
_
200 / 144 / 9
Регистрация: 08.10.2011
Сообщений: 432
10.08.2014, 19:46     Поиск минимального остовного дерева на графе #18
Цитата Сообщение от frEEze00 Посмотреть сообщение
Сравнение элементов строки между собой, для поиска минимального
зачем???
можете своими словами, "на пальцах" так сказать, объяснить как работает алгоритм Прима?
frEEze00
2 / 2 / 1
Регистрация: 10.07.2014
Сообщений: 25
10.08.2014, 20:19  [ТС]     Поиск минимального остовного дерева на графе #19
Цитата Сообщение от ya_noob Посмотреть сообщение
объяснить как работает алгоритм Прима
выбираем первую вершину(А), от нее ищем ближайшую соседнюю(Б)(для этого я и использую min). Далее нужно сравнивать расстояние от (Б) до ближайшей к ней вершине(В) и расстояние от (А) до второй ближайшей к ней вершине кроме (Б)... коряво, но что то вроде того...
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
10.08.2014, 20:40     Поиск минимального остовного дерева на графе
Еще ссылки по теме:

C++ Визуализация построения минимального остовного дерева
C++ Поиск минимального листа дерева
Поиск значения минимального листа дерева/ошибка C++

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
ya_noob
_
200 / 144 / 9
Регистрация: 08.10.2011
Сообщений: 432
10.08.2014, 20:40     Поиск минимального остовного дерева на графе #20
Цитата Сообщение от frEEze00 Посмотреть сообщение
выбираем первую вершину(А), от нее ищем ближайшую соседнюю(Б)(для этого я и использую min). Далее нужно сравнивать расстояние от (Б) до ближайшей к ней вершине(В) и расстояние от (А) до второй ближайшей к ней вершине кроме (Б)... коряво, но что то вроде того...
ну в принципе так. а давай теперь представим что надо в графе из 100 вершин найти это MST (minimal spanning tree, или минимальное остовное дерево). итак, на каком-то шаге 50 вершин уже находятся в MST и есть довольно много кандидатов попасть в MST на следующем шаге.
каковы дальнейшие действия? т.е. по какой строке матрицы ты хочешь пройтись, чтобы выбрать из этих кандидатов вершину с наименьшей стоимостью ребра?
Yandex
Объявления
10.08.2014, 20:40     Поиск минимального остовного дерева на графе
Ответ Создать тему
Опции темы

Текущее время: 14:40. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru