Форум программистов, компьютерный форум, киберфорум
Наши страницы
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 20, средняя оценка - 4.70
frEEze00
2 / 2 / 4
Регистрация: 10.07.2014
Сообщений: 25
#1

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

10.08.2014, 15:22. Просмотров 5051. Ответов 27
Метки нет (Все метки)

Переделал программу найденную в интернете, написал через функцию.
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. Помогите пожалуйста, всю голову уже сломал.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
10.08.2014, 15:22
Я подобрал для вас темы с готовыми решениями и ответами на вопрос Поиск минимального остовного дерева на графе (C++):

Поиск минимального остовного дерева на графе
Доброго времени суток, не могу уже несколько дней сделать лабораторку по...

Визуализация построения минимального остовного дерева
Помогите написать код для визуализации построения минимального остовного дерева...

Поиск минимального листа дерева
привет всем, очень нужна ваша помощь, помогите пожалуйста. поиск минимального...

Поиск минимального элемента идеально сбалансированного дерева
Как найти минимальный элемент? Вообще не представляю. зы. Дерево поиска...

Поиск значения минимального листа дерева/ошибка
всем привет, такая проблема: в чем ошибка поиска значения минимального листа?...

Поиск остовного леса методом Соллина
Доброго времени суток. Передо мной встала задача найти остовной лес минимальной...

27
zss
Модератор
Эксперт С++
6956 / 6518 / 4138
Регистрация: 18.12.2011
Сообщений: 17,208
Завершенные тесты: 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].
0
frEEze00
2 / 2 / 4
Регистрация: 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;
}
0
ya_noob
_
314 / 148 / 27
Регистрация: 08.10.2011
Сообщений: 432
10.08.2014, 16:27 #4
Цитата Сообщение от frEEze00 Посмотреть сообщение
Переделал программу найденную в интернете
хреново переделали видать, т.к. в строке 50 (в первом посте) операция бессмысленна, min не должен здесь менять значение. скорее всего есть и другие ошибки переделки.
Цитата Сообщение от zss Посмотреть сообщение
У Вас везде считается, что индексы массива в диапазоне [1:kolVer]
...
А на самом деле индексы массива в диапазоне [0:kolVer-1].
А НА САМОМ ДЕЛЕ там всё правильно, в строках 92-100 (в первом посте) написано почему и менять индексы не нужно.
Цитата Сообщение от frEEze00 Посмотреть сообщение
вот код программы, которую я нашел в интернете и переделал, она работает
мечетесь, мечетесь от одного решения к другому. а как хоть этот метод поиска остовного дерева называется то? может вначале теорию почитать про поиск остовных деревьев и написать свое осмысленное решение, а не шариться по нету в поисках готового.
0
frEEze00
2 / 2 / 4
Регистрация: 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)
0
ya_noob
_
314 / 148 / 27
Регистрация: 08.10.2011
Сообщений: 432
10.08.2014, 17:46 #6
Цитата Сообщение от frEEze00 Посмотреть сообщение
min должен менять значение, так как по другому ты не сможешь сравнивать элементы. и в исходной программе min меняет значение
ну если так, то что делает эта строка (сторка 46 из 1-го поста)
C++
1
if (cost[i][j]<min)
0
frEEze00
2 / 2 / 4
Регистрация: 10.07.2014
Сообщений: 25
10.08.2014, 18:02  [ТС] #7
Цитата Сообщение от ya_noob Посмотреть сообщение
ну если так, то что делает эта строка (строка 46 из 1-го поста)

сравниваем элемент массива с минимальным(в первом случае минимальный у нас равен максимальному), если cost[i][j]<min, то проверяем переменную used на не ложь(в первом случае она правда), а далее как раз и присваиваем значение cost[i][j] переменной min.
0
ya_noob
_
314 / 148 / 27
Регистрация: 08.10.2011
Сообщений: 432
10.08.2014, 18:12 #8
Цитата Сообщение от frEEze00 Посмотреть сообщение
сравниваем элемент массива с минимальным(в первом случае минимальный у нас равен максимальному), если cost[i][j]<min, то проверяем переменную used на не ложь(в первом случае она правда), а далее как раз и присваиваем значение cost[i][j] переменной min.
всё фигня давай по новой.
перевести с языка программирования на русский я и сам могу. я просил написать в чем СМЫСЛ данной строки.
подсказки:
1. не элемент массива, а элемент матрицы
2. элемент матрицы - это элемент матрицы смежности, которой представлен граф
3. наводящий вопрос: когда мы пробегаемся по матрице смежности, что мы должны проверить в первую очередь?
0
frEEze00
2 / 2 / 4
Регистрация: 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, с четвертой не связана..
и так далее...

а проверить мы должны в первую очередь, использовалась ли эта вершина ранее, если да, то игнорировать эту строку и столбец.
0
ya_noob
_
314 / 148 / 27
Регистрация: 08.10.2011
Сообщений: 432
10.08.2014, 18:29 #10
Цитата Сообщение от frEEze00 Посмотреть сообщение
Матрица - это двумерный массив
и всё же писать "матрица" уместнее, чем "массив", не возникает двусмысленности. ладно это всё семантика. а вот теперь по делу
Цитата Сообщение от frEEze00 Посмотреть сообщение
а проверить мы должны в первую очередь, использовалась ли эта вершина ранее
есть действие с матрицей, которое надо совершить еще раньше. что же это?
0
frEEze00
2 / 2 / 4
Регистрация: 10.07.2014
Сообщений: 25
10.08.2014, 18:37  [ТС] #11
Цитата Сообщение от ya_noob Посмотреть сообщение
есть действие с матрицей, которое надо совершить еще раньше. что же это?
сдаюсь, и какое же?
0
ya_noob
_
314 / 148 / 27
Регистрация: 08.10.2011
Сообщений: 432
10.08.2014, 18:42 #12
Цитата Сообщение от frEEze00 Посмотреть сообщение
сдаюсь, и какое же?
эээх, так не интересно.
правильный ответ (пишу с сожалением):
а первым делом надо убедиться что есть ребро из вершины i в вершину j, что в программе и делается с помощью инструкции cost[i][j]<min, где в min лежит некоторое сигнальное значение, означающее, что нет ребра в ячейке. в строках 97-98 это четко написано.
теперь надеюсь ясно почему min нельзя менять
0
frEEze00
2 / 2 / 4
Регистрация: 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 столбец. и так же искать минимальное значение.
0
ya_noob
_
314 / 148 / 27
Регистрация: 08.10.2011
Сообщений: 432
10.08.2014, 19:09 #14
Цитата Сообщение от frEEze00 Посмотреть сообщение
А min, мне кажется, мы всё равно должны менять.
скорее всего в строке 46 вместо min должно стоять что-другое, строка 50 тоже смущает (без всякой причины меняется переменная min), в строке 54 тоже какая-то хрень (2 раза одно и то же) и тд и тп. в общем, какой-то подозрительный алгоритм.
0
frEEze00
2 / 2 / 4
Регистрация: 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[] как раз за это и отвечает...
0
ya_noob
_
314 / 148 / 27
Регистрация: 08.10.2011
Сообщений: 432
10.08.2014, 19:30 #16
Цитата Сообщение от frEEze00 Посмотреть сообщение
все норм, так и должно быть min
осссссспади! опять двадцать пять. зачем мы целую страницу исписали то?
начинаем всё заново (по последней версии функции):
строка 6: мы договорились, что это проверка на наличие ребра i->j или как?
0
frEEze00
2 / 2 / 4
Регистрация: 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;}
    }
}
Когда ввожу матрицу, сразу заменяю нули на максимальное, чтобы потом не мешали в сравнение.
0
ya_noob
_
314 / 148 / 27
Регистрация: 08.10.2011
Сообщений: 432
10.08.2014, 19:46 #18
Цитата Сообщение от frEEze00 Посмотреть сообщение
Сравнение элементов строки между собой, для поиска минимального
зачем???
можете своими словами, "на пальцах" так сказать, объяснить как работает алгоритм Прима?
0
frEEze00
2 / 2 / 4
Регистрация: 10.07.2014
Сообщений: 25
10.08.2014, 20:19  [ТС] #19
Цитата Сообщение от ya_noob Посмотреть сообщение
объяснить как работает алгоритм Прима
выбираем первую вершину(А), от нее ищем ближайшую соседнюю(Б)(для этого я и использую min). Далее нужно сравнивать расстояние от (Б) до ближайшей к ней вершине(В) и расстояние от (А) до второй ближайшей к ней вершине кроме (Б)... коряво, но что то вроде того...
0
ya_noob
_
314 / 148 / 27
Регистрация: 08.10.2011
Сообщений: 432
10.08.2014, 20:40 #20
Цитата Сообщение от frEEze00 Посмотреть сообщение
выбираем первую вершину(А), от нее ищем ближайшую соседнюю(Б)(для этого я и использую min). Далее нужно сравнивать расстояние от (Б) до ближайшей к ней вершине(В) и расстояние от (А) до второй ближайшей к ней вершине кроме (Б)... коряво, но что то вроде того...
ну в принципе так. а давай теперь представим что надо в графе из 100 вершин найти это MST (minimal spanning tree, или минимальное остовное дерево). итак, на каком-то шаге 50 вершин уже находятся в MST и есть довольно много кандидатов попасть в MST на следующем шаге.
каковы дальнейшие действия? т.е. по какой строке матрицы ты хочешь пройтись, чтобы выбрать из этих кандидатов вершину с наименьшей стоимостью ребра?
0
10.08.2014, 20:40
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
10.08.2014, 20:40
Привет! Вот еще темы с решениями:

Поиск циклов в графе. Поиск центра взвешенного графа
В интернете, к сожалению, по этим вопросам не так уж много нашел. Можете...

Поиск на графе
Доброго времени суток. Мне не совсем понятна реализация в коде поиска на графе...

Поиск Ф-циклов в графе
Нужно вывести на печать все фундаментальные циклы графа. Мой код выводит...

Поиск мостов в графе
Доброй ночи,задача состоит в отыскании мостов в графе. Много где есть в...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru