Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.73/63: Рейтинг темы: голосов - 63, средняя оценка - 4.73
0 / 0 / 0
Регистрация: 29.11.2010
Сообщений: 7
1

Жадный алгоритм для определения последовательности обхода городов.

05.01.2011, 16:48. Просмотров 11964. Ответов 25
Метки нет (Все метки)


Здравствуйте! Изучаю разные транспортные алгоритмы и возник следующий вопрос.

На основе данных, полученных из txt-файла формирую двумерный массив: матрицу смежности ras[i][j], в которой хранятся расстояния между городами. Пытаюсь применить жадный алгоритм для составления последовательности обхода городов. В 0-й строке ищу минимальный элемент, запоминаю индекс в массив mashrut[n] и перехожу в строку с этим индексом. Там снова ищу минимальный элемент и т.д. После того, как нашёл минимальный элемент в строке - зануляю весь его столбец (всё равно в эту вершину больше заходить не будем). И ищу дальше. Но последовательность всё равно выдаёт неверную - 1, 2, 3, 4, 5. Вместо 1, 3, 5, 2, 4. Подскажите пожалуйста!



Добавлено через 46 минут
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
for(j=0;j<kolvo;j++)
{       double mvstr=1000;
        if(ras[i][j]<mvstr && ras[i][j]!=0)
        {
            mvstr=ras[i][j];
            printf("%lf !!", mvstr);
            marshrut[n]=j;
            i=j;
            int stolbec=j;
            n++;
            for(int ii=0; ii<kolvo; ii++)
            {
                ras[ii][stolbec]=0;
            }
        }
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
05.01.2011, 16:48
Ответы с готовыми решениями:

Составить алгоритм определения последовательности номеров удаляемых спортсменов
ребята! до завтра ришите задачу. пожалуйста. я ноль в программировании по кругу стоят N...

Жадный алгоритм
Задача: По следам олимпиады. Известно, что оптимальным выбором лыж является такой, когда длина лыж...

Жадный алгоритм
Нужно сделать проверку на правильность жадного алгоритма, доказать, что его решение единственно...

жадный алгоритм
написать программу для жадного алгоритма, если не сложно с комментариями в действиях

25
Эксперт С++
4710 / 2535 / 753
Регистрация: 18.08.2009
Сообщений: 4,550
05.01.2011, 18:14 2
Цитата Сообщение от Taymyr Посмотреть сообщение
выдаёт неверную - 1, 2, 3, 4, 5. Вместо 1, 3, 5, 2, 4.
Могу предположить что нулевая вершина связана с вершинами 1,2,3,4,5, причем расстояния от нулевой вершины до указанных идут по убыванию.

Цитата Сообщение от Taymyr Посмотреть сообщение
После того, как нашёл минимальный элемент в строке - зануляю весь его столбец (всё равно в эту вершину больше заходить не будем). И ищу дальше.
Для того что бы найти минимальный элемент в строке, нужно сначало всю строку пройти. А потом уже делать вот это:

Цитата Сообщение от Taymyr Посмотреть сообщение
printf("%lf !!", mvstr);
marshrut[n]=j;
i=j;
int stolbec=j;
n++;
for(int ii=0; ii<kolvo; ii++)
{
ras[ii][stolbec]=0;
}
А у вас обнуление столбцов и запись элементов в массив marshrut[] происходит несколько раз для одной строки.
1
0 / 0 / 0
Регистрация: 29.11.2010
Сообщений: 7
06.01.2011, 18:52  [ТС] 3
Т.е. надо в место "СЮДА???" ещё какой-то цикл?
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
for(j=1;j<kolvo;j++)
{       double mvstr=1000;
        if(ras[i][j]<mvstr && ras[i][j]!=0)
        {   
            mvstr=ras[i][j];
        }
            СЮДА?????
            ras[j][i]=0;
            waypoint[n+1]=j;
            i=j;
            int stolbec=j;
            n++;
            printf("%lf !!", mvstr);
                for(int ii=0; ii<kolvo; ii++)
                {
                ras[ii][stolbec]=0;
                }
}
0
Эксперт С++
4710 / 2535 / 753
Регистрация: 18.08.2009
Сообщений: 4,550
06.01.2011, 22:54 4
Taymyr, Лучше весь код покажите. Пока то что я вижу неправильно. У Вас нет:
Цитата Сообщение от Taymyr Посмотреть сообщение
В 0-й строке ищу минимальный элемент, запоминаю индекс в массив mashrut[n] и перехожу в строку с этим индексом. Там снова ищу минимальный элемент и т.д.
после перехода в новую строку, поиска минимального элемента с начала этой строки.
0
программист С++
841 / 600 / 147
Регистрация: 19.12.2010
Сообщений: 2,014
06.01.2011, 23:33 5
Алгоритм Прима
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
#include <algorithm>
#include <fstream>
#include <conio.h>
#include <vector>
#include <iostream>
#include <iterator>
 
using namespace std;
 
#define INF 1000000000
 
int main()
{
    fstream in("a.txt");
    if (in.fail())
    {
        cout << "Cannot open the file\n";
        _getch();
        exit(EXIT_FAILURE);
    }
    int n;
    in >> n;
    vector<vector<int> > g(n, vector<int>(n));
    for(vector<vector<int> >::iterator i = g.begin(), end = g.end(); i != end; ++i)
        for(vector<int>::iterator j = i->begin(), jend = i->end(); j != jend ; ++j)
            in >> *j;
 
    // алгоритм
    vector<bool> used (n);
    vector<int> min_e (n, INF), sel_e (n, -1);
    min_e[0] = 0;
    for (int i = 0; i < n; ++i)
    {
        int v = -1;
        for (int j = 0; j < n; ++j)
            if (!used[j] && (v == -1 || min_e[j] < min_e[v]))
                v = j;
        if (min_e[v] == INF)
        {
            cout << "No MST!";
            exit(0);
        }
 
        used[v] = true;
        if (min_e[v] != -1)
            cout << v << " " << min_e[v] << endl;
 
        for (int to = 0; to < n; ++to)
            if (g[v][to] < min_e[to])
            {
                min_e[to] = g[v][to];
                sel_e[to] = v;
            }
    }
    _getch();
    return EXIT_SUCCESS;
}
1
0 / 0 / 0
Регистрация: 29.11.2010
Сообщений: 7
07.01.2011, 09:31  [ТС] 6
Валерий, вот. Пишу сам, поэтому взгляду со стороны изъяны виднее
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
for (i=0; i<p; i++)             //Заполняем матрицу смежности ras[i][j] длинами путей
                for (j=0; j<p; j++)
                {
                        ras[i][j] = sqrt(pow(a[i*2]-a[j*2], 2) + pow(a[i*2+1]-a[j*2+1], 2));
                }
 
        
 
 
 
for(i=0;i<p;i++)                //Выводим на печать матрицу смежности
{
    for(j=0;j<p;j++)
    {
        printf("%lf ", ras[i][j]);
    }
    printf("\n");
}
 
int *marshrut;                  
marshrut=new int[kolvo+1];          //Выделяем память под массив содержащий маршрут
 
 
printf("\n");
i=0;                        //Фиксируем i. Всегда начнём проверять с 0 строки.
int n=0;
marshrut[n]=0;                  //Всегда первый элемент в маршруте - 0. 
for(j=1;j<kolvo;j++)                //Начинаем просмотр в строке
{       double mvstr=1000;
        if(ras[i][j]<mvstr && ras[i][j]!=0) //Если элемент меньше mvstr и ненулевой - он минимальный
        {   
            mvstr=ras[i][j];
        }
            
            ras[j][i]=100000;   //Присваиваем заведомо большое значение этому же элементу, лежащему по другую сторону диагонали (чтобы гарантированно он не был минимальным)
            marshrut[n+1]=j;    //Записываем в массив номер столбца этого элемента
            i=j;            //Фиксируем строку i. В ней будем искать дальше минимальный элемент.
            int stolbec=j;      //Фиксируем номер столбца, чтобы заполнить его заведомо большими значениями 
            n++;            //Сдвигаем n на 1
            printf("%lf !!", mvstr);//Заполняем столбец.
                for(int ii=0; ii<kolvo; ii++)
                {
                ras[ii][stolbec]=100000;
                }
}
0
Эксперт С++
4710 / 2535 / 753
Регистрация: 18.08.2009
Сообщений: 4,550
07.01.2011, 09:58 7
Попробуйте вот это:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
for(j=1;j<kolvo;j++)                            //Начинаем просмотр в строке
{       double mvstr=1000;
                if(ras[i][j]<mvstr && ras[i][j]!=0) //Если элемент меньше mvstr и ненулевой - он минимальный
                {       
                        mvstr=ras[i][j];
                }
                        
                        ras[j][i]=100000;       //Присваиваем заведомо большое значение этому же элементу, лежащему по другую сторону диагонали (чтобы гарантированно он не был минимальным)
                        marshrut[n+1]=j;        //Записываем в массив номер столбца этого элемента
                        i=j;                    //Фиксируем строку i. В ней будем искать дальше минимальный элемент.
                        int stolbec=j;          //Фиксируем номер столбца, чтобы заполнить его заведомо большими значениями 
                        n++;                    //Сдвигаем n на 1
                        printf("%lf !!", mvstr);//Заполняем столбец.
                                for(int ii=0; ii<kolvo; ii++)
                                {
                                ras[ii][stolbec]=100000;
                                }
}
заменить на:
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
while(n<colvo-1)
{
    double mvstr=1000;
    int j_temp=0;
    if(i==0) j_temp=1;
    for(j=0;j<kolvo;j++)                            //Начинаем просмотр в строке
    {   
        if(ras[i][j]<mvstr && ras[i][j]!=0) //Если элемент меньше mvstr и ненулевой - он минимальный
        {                               
            mvstr=ras[i][j];
            j_temp=j;
        }
    }
    ras[j_temp][i]=100000;       //Присваиваем заведомо большое значение этому же элементу, лежащему по другую сторону диагонали (чтобы гарантированно он не был минимальным)
    marshrut[n+1]=j_temp;        //Записываем в массив номер столбца этого элемента
    i=j_temp;                    //Фиксируем строку i. В ней будем искать дальше минимальный элемент.
    int stolbec=j_temp;          //Фиксируем номер столбца, чтобы заполнить его заведомо большими значениями 
    n++;                    //Сдвигаем n на 1
    printf("%lf !!", mvstr);//Заполняем столбец.
    for(int ii=0; ii<kolvo; ii++)
    {
        ras[ii][stolbec]=100000;
    }
}
1
0 / 0 / 0
Регистрация: 29.11.2010
Сообщений: 7
07.01.2011, 10:28  [ТС] 8
Валерий, спасибо Вам большое за помощь!
p.s. Если кому понадобится код, то вариант Валерия работает. Только не забудьте 0 столбец заполнить заведомо большими значениями, чтобы он в него не возвращался:

C++
1
2
3
4
5
6
7
while(n<kolvo)
{
        for(int ii=0; ii<kolvo; ii++)
        {
                prices[ii][0]=100000;
        }
....
0
0 / 0 / 0
Регистрация: 18.03.2012
Сообщений: 7
18.03.2012, 16:57 9
Выложите пожалуйста полный код на С++ жадного алгоритма...очень надо(
0
Эксперт С++
4710 / 2535 / 753
Регистрация: 18.08.2009
Сообщений: 4,550
18.03.2012, 17:35 10
Цитата Сообщение от светлана1990 Посмотреть сообщение
Выложите пожалуйста полный код на С++ жадного алгоритма...очень надо(
Кода на С++ жадного алгоритма в готовом виде не существует. Вы лучше опишите задачу, которую нужно решить и если в решении можно использовать жадный алгоритм, то помогу.
0
0 / 0 / 0
Регистрация: 18.03.2012
Сообщений: 7
18.03.2012, 19:14 11
Мне нужно решить задачу коммивояжера с помощью жадного алгоритма. Программа должна вычислять кратчайший путь по заданным точкам.Буду благодарна за помощь
0
Эксперт С++
4710 / 2535 / 753
Регистрация: 18.08.2009
Сообщений: 4,550
18.03.2012, 19:54 12
Цитата Сообщение от светлана1990 Посмотреть сообщение
Мне нужно решить задачу коммивояжера с помощью жадного алгоритма.
Вы в курсе, что жадный алгоритм может выдавать неправильное решение - он не эффективен для этой задачи.

Добавлено через 18 минут
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
#include<iostream>
using namespace std;
#define n 100
int main()
{
    int N, mas[n][n]={0}, i, j, mas_res[n-1], res=0, min, tmp=0;
    bool mas1[n]={false};
    cout<<"Kol-vo gorodov: ";
    cin>>N;
    for(i=0; i<N-1; i++)
        for(j=i+1; j<N; j++)
        {
            cout<<"Rast megdu "<<i+1<<" i "<<j+1<<"gorodom: ";
            cin>>mas[i][j];
            mas[j][i]=mas[i][j];
        }
    mas1[0]=true;
    for(i=0; i<N-1; i++)
    {
        min=-1;
        for(j=0; j<N; j++)
            if(!mas1[j] && mas[tmp][j]>0)
            {
                if(min==-1) min=j;
                else
                {
                    if(mas[tmp][j]<mas[tmp][min])
                        min=j;
                }
            }
        mas_res[res++]=min;
        mas1[min]=true;
        tmp=min;
    }
    cout<<"Poluchen put:"<<endl;
    cout<<"1 ";
    for(i=0; i<N-1; i++)
        cout<<mas_res[i]+1<<" ";
    cout<<"1 "<<endl;
    return 0;
}
1
0 / 0 / 0
Регистрация: 18.03.2012
Сообщений: 7
18.03.2012, 21:14 13
Спасибо за программу))
Я знаю, что неэффективен способ, но мне это и надо))Я пишу магистерскую работу и мне нужно исследовать два метода для движения управления роботом по заданной траектории, вот я и покажу что этот метод хуже ну и буду уже работать и улучшать другой))Еще раз спасибо

Добавлено через 9 минут
хотелось бы еще узнать некоторые нюансы..как работает эта программа?я так понимаю в конце она выдает путь, который считает оптимальным, а где указывать матрицу ну или расстояние между пунктами?если не сложно,объясните, просто в с++ вообще ничего не понимаю...((
0
Эксперт С++
4710 / 2535 / 753
Регистрация: 18.08.2009
Сообщений: 4,550
18.03.2012, 21:21 14
Цитата Сообщение от светлана1990 Посмотреть сообщение
я так понимаю в конце она выдает путь, который считает оптимальным,
так и есть.

Цитата Сообщение от светлана1990 Посмотреть сообщение
а где указывать матрицу ну или расстояние между пунктами?
Вы запустите программу. Там будут сообщения типа:
Rast megdu 3 i 4 gorodom:
(что значит введите расстояние между 3 и 4 городом). Вы вводите значения этого расстояния.
0
9 / 9 / 1
Регистрация: 26.11.2009
Сообщений: 78
19.03.2012, 22:25 15
Доброго времени суток!

У меня только один вопрос, это алгоритм Коммивояжера реализованный методом перебора?
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
#include<iostream>
using namespace std;
#define n 100
int main()
{
        int N, mas[n][n]={0}, i, j, mas_res[n-1], res=0, min, tmp=0;
        bool mas1[n]={false};
        cout<<"Kol-vo gorodov: ";
        cin>>N;
        for(i=0; i<N-1; i++)
                for(j=i+1; j<N; j++)
                {
                        cout<<"Rast megdu "<<i+1<<" i "<<j+1<<"gorodom: ";
                        cin>>mas[i][j];
                        mas[j][i]=mas[i][j];
                }
        mas1[0]=true;
        for(i=0; i<N-1; i++)
        {
                min=-1;
                for(j=0; j<N; j++)
                        if(!mas1[j] && mas[tmp][j]>0)
                        {
                                if(min==-1) min=j;
                                else
                                {
                                        if(mas[tmp][j]<mas[tmp][min])
                                                min=j;
                                }
                        }
                mas_res[res++]=min;
                mas1[min]=true;
                tmp=min;
        }
        cout<<"Poluchen put:"<<endl;
        cout<<"1 ";
        for(i=0; i<N-1; i++)
                cout<<mas_res[i]+1<<" ";
        cout<<"1 "<<endl;
        return 0;
}
Добавлено через 1 час 1 минуту
Так же интересует, почему используем данное условие:
C++
1
if(!mas1[j] && mas[tmp][j]>0)
Объясните пожалуйста, как можно подробней. Спасибо.
0
Эксперт С++
4710 / 2535 / 753
Регистрация: 18.08.2009
Сообщений: 4,550
20.03.2012, 01:48 16
Цитата Сообщение от palamarchukn Посмотреть сообщение
У меня только один вопрос, это алгоритм Коммивояжера реализованный методом перебора?
это решение задачи Коммивояжера с помощью жадного алгоритма, которое неэффективно для этой задачи.

Цитата Сообщение от palamarchukn Посмотреть сообщение
Так же интересует, почему используем данное условие:
см комментарии:
C++
1
if(!mas1[j] && mas[tmp][j]>0)// !mas1[j] - если город j еще не посещали и mas[tmp][j]>0 - путь из города в котором находимся tmp в город j есть
1
9 / 9 / 1
Регистрация: 26.11.2009
Сообщений: 78
20.03.2012, 04:22 17
Спасибо большое! Но у меня есть еще вопросы.

C++
1
2
3
using namespace std; // Если поместить using namespsce std; то все последующие операторы будут брать переменные и ф-ции из области std
#define n 100        // //кол-во эл-в массива
int _tmain(int argc, _TCHAR* argv[])
Правильно ли я закоментил?

И еще для чего мы делаем это?
C++
1
2
mas1[min]=true; // 
              tmp=min; //
0
Эксперт С++
4710 / 2535 / 753
Регистрация: 18.08.2009
Сообщений: 4,550
20.03.2012, 06:13 18
Цитата Сообщение от palamarchukn Посмотреть сообщение
Правильно ли я закоментил?
да

Цитата Сообщение от palamarchukn Посмотреть сообщение
И еще для чего мы делаем это?
C++
1
2
3
// перед этим нашли, что самый короткий путь из вершины где сейчас находимся tmp лежит в врешину с индексом min
mas1[min]=true; // помечаем вершину min как пройденную
              tmp=min; // считаем что вершина где сейчас находимся - вершина с индексом min (переходим из вершины tmp в вершину min)
1
9 / 9 / 1
Регистрация: 26.11.2009
Сообщений: 78
02.04.2012, 18:40 19
Может быть кому пригодится:

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
// KomiV.cpp: определяет точку входа для консольного приложения.
//
#include "stdafx.h" // заголовочный файл 
#include <iostream> // заголовочный файл с классами, функциями и переменными для организации ввода-вывода в языке программирования C++
#include "conio.h"  // заголовочный файл, используемый в старых компиляторах, работающих в операционных системах MS-DOS, для создания текстового интерфейса пользователя.
                    // в данном случае использовали для останова. ( чтобы консоль незакрывалась после ее выполнения)
#include <clocale>  // заголовочный файл стандартной библиотеки языка программирования С, который используется для задач, связанных с локализацией.
                    // в данном случае исплоьзовали для подключения библиотеку русского языка
using namespace std; // Если поместить using namespsce std; то все последующие операторы будут брать переменные и ф-ции из области std
#define n 100        // //кол-во эл-в массива
int _tmain(int argc, _TCHAR* argv[])  
{
   setlocale(LC_CTYPE, "rus"); // использование библ-ки русского языка
      int N, mas[n][n]={0}, i, j, mas_res[n-1], res=0, min, tmp=0;   // обычное заполнение массива. 
      bool mas1[n]={false};
      cout<<"Количество городов: ";
      cin>>N;
 
      for(i=0; i<N-1; i++) // Берется N-ый город
              for(j=i+1; j<N; j++) // и заполняется расстояние между ним и остальными городами
              {
                      cout<<"Расстояние между "<<i+1<<" и "<<j+1<<"  "<<" городом: ";
  cin>>mas[i][j]; 
                      mas[j][i]=mas[i][j];
              }
      mas1[0]=true;
      for(i=0; i<N-1; i++) // цикл по городам
      {
              min=-1; // начальное значение минимума
              for(j=0; j<N; j++)// цикл по расстояниям между городом, из вышенаписанного цикла и остальными городами
                    if(!mas1[j] && mas[tmp][j]>0)// !mas1[j] - если город j еще не посещали и mas[tmp][j]>0 - путь из города в котором находимся tmp в город j есть
                      {
                              if(min==-1) min=j; // если минимум равен -1, то минимум присвоить индексу
                                                // если не -1, то сравниваем значения и ищем минимальное среди них
                              else
                              { // ну тут считаем все делается аналогично циклу заполнение расстояний
                                // только тут вместо того, чтобы вводить значения в массивы между городами,
                                // их тут сравнивают. берут расстояние между первым и второым городом и сравнивается с 1ым и 3им.
                                // потом 1ым и 4ым и так далее. Увеличили i, город уже стал вторым и заново пошел цикл. Между 2ым и 3им городом
                                 // т.к. между 2ым и 1ым городом сравнение было б на предыдущем этапе, когда i=1 (ну 1ый город со 2ым сравнивали). 
                                 // смысл еще раз сравнивать 2ой с 1ым)) 
                                      if(mas[tmp][j]<mas[tmp][min])
                                              min=j;
                              }
                      }
              mas_res[res++]=min; // записали это минимальное расстояние
                                  // перед этим нашли, что самый короткий путь из вершины где сейчас находимся tmp лежит в врешину с индексом min
              mas1[min]=true;     // помечаем вершину min как пройденную
                  tmp=min;        // считаем что вершина где сейчас находимся - вершина с индексом min (переходим из вершины tmp в вершину min)
 
  }
      cout<<"Получен путь:"<<endl;
      cout<<"1 ";
      for(i=0; i<N-1; i++)         // обычный вывод результирующего массива
              cout<<mas_res[i]+1<<" ";
      cout<<"1 "<<endl;   
      _getch();
return 0;
 
}
0
0 / 0 / 0
Регистрация: 13.11.2012
Сообщений: 8
23.11.2012, 21:32 20
светлана1990, пришли мне, пожалуйста, твою решенную задачу коммивояжера с помощью жадного алгоритма
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
23.11.2012, 21:32

Заказываю контрольные, курсовые, дипломные и любые другие студенческие работы здесь или здесь.

Жадный алгоритм
Суть задачи - имеется N предметов различного размера. Один ящик имеет строгую вместимость....

Жадный алгоритм С++
С целью борьбы с теневой экономикой банк решил внедрить объединение N счетов фирмы в один. За одну...

Жадный алгоритм
Добрый день. Помогите, пожалуйста, понять, где затаилась ошибка. Это задачка на жадный алгоритм:...

Жадный граф/алгоритм
Требуется написать программу с графическим интерфейсом: пользователь задаёт точки (A, B, C и...


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

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

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