Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- TForm1 * Form1;
- int N, M; //Размерность задачи
- float * a; //адрес массива запасов поставщиков
- float * b; //адрес массива потребностей потребителей
- float ** C; //адрес массива(двумерного) стоимости перевозки
- float ** X; //адрес массива(двумерного) плана доставки
- float * u; //адрес массива потенциалов поставщиков
- float * v; //адрес массива потенциалов потребителей
- float ** D; //адрес массива(двумерного) оценок свободных ячеек таблицы
- bool stop; //признак достижения оптимального плана
- bool ** T; //массив будет хранить коодинаты ячеек, в коорые уже вписывались
- //--------------------------Метод потенциалов
- float find1, find2; //величина перераспределения поставки для цикла
- float best1 = 0; //наилучшая оценка улучшения среди всех допустимых перераспределений
- float best2 = 0;
- int ib1 = -1;
- int jb1 = -1;
- int ib2 = -1;
- int jb2 = -1;
- //Ищем наилучший цикл перераспределения поставок:
- for (int i = 0; i < N; i++)
- for (int j = 0; j < M; j++)
- if (D[i][j] < 0) //Идём по ВСЕМ ячейкам с отрицательной оценкой
- { //и ищем допустимые циклы перераспределения ДЛЯ КАЖДОЙ такой ячейки
- //Обнуляем матрицу Y:
- for (int i = 0; i < N; i++)
- for (int j = 0; j < M; j++)
- Y[i][j] = 0;
- //Ищем цикл для ячейки с оценкой D[i][j]:
- find1 = find_gor(i, j, i, j, N, M, X, Y, 0, -1); //Начинаем идти по горизонтали
- //Обнуляем матрицу Y:
- for (int i = 0; i < N; i++)
- for (int j = 0; j < M; j++)
- Y[i][j] = 0;
- find2 = find_ver(i, j, i, j, N, M, X, Y, 0, -1); //Начинаем по вертикали
- if (find1 > 0)
- if (best1 > D[i][j] * find1) {
- best1 = D[i][j] * find1; //наилучшая оценка
- ib1 = i; //запомминаем координаты ячейки
- jb1 = j; //цикл из которой даёт наибольшее улучшение
- }
- if (find2 > 0)
- if (best2 > D[i][j] * find2) {
- best2 = D[i][j] * find2; //наилучшая оценка
- ib2 = i; //запомминаем координаты ячейки
- jb2 = j; //цикл из которой даёт наибольшее улучшение
- }
- }
- if ((best1 == 0) && (best2 == 0)) {
- //stop=true;
- //ShowMessage("Цикл перераспределения поставок не найден");
- ok = false;
- d = d1; //откат назад
- for (int i = 0; i < N; i++)
- for (int j = 0; j < M; j++)
- if (X[i][j] == 0) X[i][j] = -1;
- continue;
- } else { //Обнуляем матрицу Y:
- for (int i = 0; i < N; i++)
- for (int j = 0; j < M; j++)
- Y[i][j] = 0;
- //возвращаемся к вычислению цикла с наилучшим перераспределением:
- int ib, jb;
- if (best1 < best2) {
- find_gor(ib1, jb1, ib1, jb1, N, M, X, Y, 0, -1);
- ib = ib1;
- jb = jb1;
- } else {
- find_ver(ib2, jb2, ib2, jb2, N, M, X, Y, 0, -1);
- ib = ib2;
- jb = jb2;
- }
- for (int i = 0; i < N; i++) {
- for (int j = 0; j < M; j++) {
- if ((X[i][j] == 0) && (Y[i][j] < 0)) {
- stop = true;
- ok = false;
- d = d1; //откат назад
- Memo1 -> Lines -> Add("Попытка отрицательной поставки!");
- //ShowMessage("Попытка отрицательной поставки!");
- //break;
- }
- X[i][j] = X[i][j] + Y[i][j]; //перераспределяем поставки
- if ((i == ib) && (j == jb)) X[i][j] = X[i][j] + 1; //добавляем 1 (т.к. до этого было -1 )
- if ((Y[i][j] <= 0) && (X[i][j] == 0)) X[i][j] = -1; //если ячейка обнулилась, то выбрасываем её из рассмотрения
- }
- //if(stop)break;
- }
- }
- //
- Memo1 -> Lines -> Add("Матрица цикла перерасчёта:");
- Memo1 -> Lines -> Add("");
- for (int i = 0; i < N; i++)
- for (int j = 0; j < M; j++) {
- Memo1 -> Text = Memo1 -> Text + FloatToStr(Y[i][j]) + " ";
- if (j == M - 1) Memo1 -> Lines -> Add("");
- }
- Memo1 -> Lines -> Add("--------");
- //ShowMessage("Для продолжения нажмите "ОК" ");
- Memo1 -> Lines -> Add("Новый план:");
- Memo1 -> Lines -> Add("");
- float F = 0;
- for (int i = 0; i < N; i++)
- for (int j = 0; j < M; j++) {
- Memo1 -> Text = Memo1 -> Text + FloatToStr(X[i][j]) + " ";
- if (X[i][j] > 0) F = F + X[i][j] * C[i][j];
- if (j == M - 1) Memo1 -> Lines -> Add("");
- }
- Memo1 -> Lines -> Add("F=" + FloatToStr(F));
- Memo1 -> Lines -> Add("--------");
- ShowMessage("Для продолжения нажмите "
- ОК " ");
- //
- ok = true;
- for (int i = 0; i < N; i++)
- for (int j = 0; j < M; j++)
- T[i][j] = false;
- delete[] Y;
- //проверка на вырожденность: (?)
- L = 0;
- for (int i = 0; i < N; i++)
- for (int j = 0; j < M; j++)
- if (X[i][j] >= 0) L++; //подсчёт заполненных ячеек
- d = M + N - 1 - L; //если d>0,то задача - вырожденная
- d1 = d;
- if (d > 0) ok = false;
- }
- delete[] u;
- delete[] v;
- delete[] ub;
- delete[] vb;
- delete[] D;
- }
- while (stop == false);
- Memo1 -> Lines -> Add("Оптимальный план:");
- Memo1 -> Lines -> Add("");
- float Fmin = 0;
- for (int i = 0; i < N; i++)
- for (int j = 0; j < M; j++) {
- Memo1 -> Text = Memo1 -> Text + FloatToStr(X[i][j]) + " ";
- if (X[i][j] > 0) Fmin = Fmin + X[i][j] * C[i][j];
- if (j == M - 1) Memo1 -> Lines -> Add("");
- }
- Memo1 -> Lines -> Add("Fmin=" + FloatToStr(Fmin));
- delete[] X;
- delete[] C;
- delete[] a;
- delete[] b;
- }
- //---------------------------------------------------------------------------
- //Функуция поиска ячеек,подлежащих циклу перераспределения (вдоль строки)
- float TForm1::find_gor(int i_next, int j_next, int im, int jm, int n, int m, float ** X, float ** Y, int odd, float Xmin) {
- int rez = -1;
- for (int j = 0; j < m; j++) //идём вдоль строки, на которой стоим
- //ищем заполненную ячейку(кроме той,где стоим) или начальная ячейка(но уже в конце цикла:odd!=0 )
- if (((X[i_next][j] >= 0) && (j != j_next)) || ((j == jm) && (i_next == im) && (odd != 0))) {
- odd++; //номер ячейки в цикле перерасчёта(начало с нуля)
- if (odd > 1000) {
- ShowMessage("Угроза переполнения стека");
- return -1;
- }
- int Xmin_old = -1;
- if ((odd % 2) == 1) //если ячейка нечётная в цикле ( начальная- нулевая )
- {
- Xmin_old = Xmin; //Запоминаем значение минимальной поставки в цикле (на случай отката назад)
- if (Xmin < 0) Xmin = X[i_next][j]; //если это первая встреченная ненулевая ячейка
- else if ((X[i_next][j] < Xmin) && (X[i_next][j] >= 0)) {
- Xmin = X[i_next][j];
- }
- }
- if ((j == jm) && (i_next == im) && ((odd % 2) == 0)) //если замкнулся круг и цикл имеет чётное число ячеек
- {
- Y[im][jm] = Xmin; //Значение минимальной поставки, на величину которой будем изменять
- return Xmin;
- }
- //если круг еще не замкнулся - переходим к поиску по вертикали:
- else rez = find_ver(i_next, j, im, jm, n, m, X, Y, odd, Xmin); //рекурсивный вызов
- if (rez >= 0) //как бы обратный ход рекурсии(в случае если круг замкнулся)
- {
- //для каждой ячейки цикла заполняем матрицу перерасчёта поставок:
- if (odd % 2 == 0) Y[i_next][j] = Y[im][jm]; //в чётных узлах прибавляем
- else Y[i_next][j] = -Y[im][jm]; //в нечётных узлах вычитаем
- break;
- } else //откат назад в случае неудачи(круг не замкнулся):
- {
- odd--;
- if (Xmin_old >= 0) //если мы изменяли Xmin на этой итерации
- Xmin = Xmin_old;
- }
- }
- return rez; //если круг замкнулся (вернулись в исходную за чётное число шагов) -
- // возвращает найденное минимальное значение поставки в нечётных ячейках цикла,
- // если круг не замкнулся, то возвращает -1.
- }
- //-----------------------------------------------------------------------------
- //Функуция поиска ячеек,подлежащих циклу перераспределения (вдоль столбца)
- float TForm1::find_ver(int i_next, int j_next, int im, int jm, int n, int m, float ** X, float ** Y, int odd, float Xmin) {
- int rez = -1;
- int i;
- for (i = 0; i < n; i++) //идём вдоль столбца, на котором стоим
- //ищем заполненную ячейку(кроме той,где стоим) или начальная ячейка(но уже в конце цикла:odd!=0 )
- if (((X[i][j_next] >= 0)) && (i != i_next) || ((j_next == jm) && (i == im) && (odd != 0))) {
- odd++; //номер ячейки в цикле перерасчёта(начало с нуля)
- if (odd > 1000) {
- ShowMessage("Угроза переполнения стека");
- return -1;
- }
- int Xmin_old = -1;
- if ((odd % 2) == 1) //если ячейка нечётная в цикле ( начальная- нулевая )
- {
- Xmin_old = Xmin; //Запоминаем значение минимальной поставки в цикле (на случай отката назад)
- if (Xmin < 0) Xmin = X[i][j_next]; //если это первая встреченная ненулевая ячейка
- else if ((X[i][j_next] < Xmin) && (X[i][j_next] >= 0))
- Xmin = X[i][j_next];
- }
- if ((i == im) && (j_next == jm) && ((odd % 2) == 0)) //если замкнулся круг и цикл имеет чётное число ячеек
- {
- Y[im][jm] = Xmin; //Значение минимальной поставки, на величину которой будем изменять
- return Xmin;
- }
- //если круг еще не замкнулся - переходим к поиску по горизонтали:
- else rez = find_gor(i, j_next, im, jm, n, m, X, Y, odd, Xmin); //- рекурсивный вызов
- if (rez >= 0) //как бы обратный ход (в случае если круг замкнулся)
- {
- //для каждой ячейки цикла заполняем матрицу перерасчёта поставок:
- if (odd % 2 == 0) Y[i][j_next] = Y[im][jm]; //эти прибавляются
- else Y[i][j_next] = -Y[im][jm]; //эти вычитаются
- break;
- } else //откат назад в случае неудачи (круг не замкнулся):
- {
- odd--;
- if (Xmin_old >= 0) //если мы изменяли Xmin на этой итерации
- Xmin = Xmin_old;
- }
- }
- return rez;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement