- •Содержание
- •Введение
- •1 Постановка задачи оптимизации закупки топлива авиакомпанией
- •1.1 Качественное описание задачи
- •1.2 Концептуальная модель задачи
- •1.3 Математическая постановка задачи
- •2 Алгоритмизация решения задачи оптимизации закупки топлива авиакомпанией
- •2.1 Методы нахождения опорного и оптимального решения транспортной задачи
- •2.2 Описание венгерского метода нахождения оптимального плана
- •2.3 Описание алгоритма нахождения опорного плана методом северо-западного угла
- •2.4 Описание алгоритма нахождения оптимального плана распределительным методом
- •2.5 Проектирование сценария диалога
- •2.6 Описание структур данных
- •2.7 Описание программной системы «Оптимизация закупки топлива авиакомпанией»
- •2.8 Структурная схема сценария диалога и описание его программной реализации
- •2.9 Структурная схема алгоритмов метода северо-западного угла и распределительного и описание их программной реализации
- •2.10 Структурная схема алгоритмов ведения файловых архивов, графического представления результатов и их программная реализация
- •3. Численные эксперименты
- •3.1 Ручная реализация метода северо-западного угла и распределительного
- •3.2 Ручная реализация венгерского метода
- •3.3 Машинные эксперименты с программной системой
- •3.4 Качественная интерпретация полученных результатов
- •Заключение
3.2 Ручная реализация венгерского метода
Приведение матрицы стоимостей, в результате приведения по столбцам и строкам была получена матрица С0
Тогда план, построенный методом северо-западного угла в нулевых клетках имеет вид:
Суммарная невязка:∆0=0+0+0+0+0+25+0+0+17+8+0+0=50;
∆0!=0 => переход на первый шаг первой итерации:
1
.1
:
Так как все нули отмечены, а невыделенный ноль с положительной невязкой не найден, переход на шаг 3.
1.3: h=min(невыделенный элемент С0)=min(17,7,1,19,7,32,14,29)=1; Тогда:
Переход на 1.1
1
.1:
Найден 0’ с положительной невязкой в строке. Переход на 1.2
1.2: θ=min(25,8,30)=8; Тогда:
∆1=∆0-2*θ=34!=0. Переход на 2.1
2
.1
Так как все нули отмечены, а невыделенный ноль с положительной невязкой не найден, переход на шаг 3.
2.3: h=min(16,13,10,6,6,7,3,31)=3; Тогда:
Переход на 2.1
2
.1:
Найден 0’ с положительной невязкой в строке. Переход на 2.2
2.2: θ=min(17,17,47,22)=17; Тогда:
∆2=∆1-2*θ=0 => План оптимален. Его стоимость F=2614
Конец решения.
3.3 Машинные эксперименты с программной системой
Перед вычислениями был проведён проверочный запуск программы, скриншот которой представлен на рисунке 3.1
Рисунок 3.1 – Проверочный прогон программы.
Прогон вычислений программы приведен на рисунке 3.2
Рисунок 3.2 – Прогон вычислений программы.
3.4 Качественная интерпретация полученных результатов
В результате ручных и машинных расчётов разными методами был получен один и тот же результат, что свидетельствует от верности решения и исправности работы программы
В результате анализа процесса решения было установлено, что ручные вычисления лучше всего выполнять венгерским методом, однако программировать решение лучше методами северо-западного угла и распределительным.
Заключение
В ходе выполнения курсового проекта были описаны метод северо-западного угла для нахождения опорного решения и распределительный метод для нахождения оптимального решения. Разработаны структурные схемы алгоритмов, реализующих методы северо-западного угла и распределительного. Написаны на языке Си и отлажены на Intel-совместимой ЭВМ программы реализации северо-западного угла и распределительного. Разработаны программы организации диалога, ведения файловых архивов исходных данных и результатов расчетов, графического представления результатов. Выполнены ручные расчеты по оптимизации закупки топлива в соответствии с венгерским и распределительным методами, а опорное решение найти методом северо-западного угла.
В результате была получена программа вычисления транспортной задачи с удобным интерфейсом и ведением файловых архивов, а также решение транспортной задачи с заданными в 1.1 начальными условиями
Список литературы:
1. Г.А. Черноморов - Методические указания по выполнению курсовой работы дисциплины “Системный анализ и исследование операций”/ Новочерк. гос. техн. ун-т. Новочеркасск: НГТУ, 1998. С. 76.
2. Зайченко Ю.П. - Исследование операций. -Киев: Вища шк., 1979.-392с.
3. Венцель Е.С. Исследование операций.- М.: Советское радио, 1972. -552с
Приложение А - Структурная схема алгоритма нахождения опорного решения методом северо-западного угла
Приложение В – Структурная схема алгоритма нахождения оптимального решения распределительным методом.
Приложение С - Листинг программы.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
namespace trnsport
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
class Point
{
private int x;
private int y;
public Point(int i, int j)
{
x = i;
y = j;
}
public int GetX()
{
return x;
}
public int GetY()
{
return y;
}
}
void equal(ref double[][] a, double[][] b)
{
for (int i = 0; i < b.Length; i++)
{
for (int j = 0; j < b[i].Length; j++)
{
a[i][j] = b[i][j];
}
}
}
bool numof1(double[][] f, int fi, int fj)
{
int s=0;
for (int i = 0; i < f.Length; i++)
{
if (f[i][fj] == 1) s++;
if (s >= 2) return false;
}
s=0;
for (int j = 0; j < f[0].Length; j++)
{
if (f[fi][j] == 1) s++;
if (s >= 2) return false;
}
return true;
}
bool circleOfEnumerizing(ref double[][] f, int circleLength, int curi, int curj, ref List<Point> c)
{
bool cir;
int r=circleLength+1;
double[][] f1 = new double[f.Length][];
for (int i = 0; i < f.Length; i++)
{
f1[i] = new double[f[i].Length];
}
equal(ref f1, f);
if (circleLength % 2 == 0)
{
for (int i = 0; i < f1.Length; i++)
{
if (f1[i][curj]==1)
{
f1[i][curj]=3;
cir=circleOfEnumerizing(ref f1, r,i,curj,ref c);
if (cir)
{
c.Add(new Point(curi, curj));
return true;
}
else equal(ref f1,f);
}
if (f1[i][curj] == 2 && circleLength>1)
{
c.Add(new Point(curi, curj));
return true;
}
}
return false;
}
else
{
for (int i = 0; i < f1[0].Length; i++)
{
if (f1[curi][i] == 1)
{
f1[curi][i] = 3;
cir = circleOfEnumerizing(ref f1, r, curi, i, ref c);
if (cir)
{
if(circleLength>1)c.Add(new Point(curi, curj));
return true;
}
else equal(ref f1,f);
}
}
return false;
}
}
private void exec_Click(object sender, EventArgs e)
{
String[] h0 = A.Text.Split('\n');
String[] h1 = B.Text.Split('\n');
String[] h = C.Text.Split('\n');
int m = h0.Length;
int n = h1.Length;
String[] q;
double[] a = new double[m];
double[] b = new double[n];
double[][] c = new double[m][];
double[][] x = new double[m][];
double[][] f = new double[m][];
for (int i = 0; i < n; i++)
{
try
{
b[i] = Convert.ToDouble(h1[i]);
}
catch (Exception ex)
{
X.Text = "Ошибка!\nЗначения нужд потребителей введены некорректно. Исправьте ошибку и повторите попытку";
return;
}
}
for (int i = 0; i < m; i++)
{
try
{
q = h[i].Split(' ');
}
catch (Exception ex)
{
X.Text = "Ошибка!\nРазмерность матрицы стоимостей перевозок единицы товара не соответствует количеству поставщиков и/или потребителей. Возможно, вы пропустили некоторые строки/столбцы. Исправьте ошибку и повторите попытку";
return;
}
try
{
a[i] = Convert.ToDouble(h0[i]);
}
catch (Exception ex)
{
X.Text = "Ошибка!\nЗначения запасов поставщиков введены некорректно. Исправьте ошибку и повторите попытку";
return;
}
c[i] = new double[n];
x[i] = new double[n];
f[i] = new double[n];
for (int j = 0; j < n; j++)
{
try
{
c[i][j] = Convert.ToDouble(q[j]);
}
catch (Exception ex)
{
X.Text = "Ошибка!\nЗначения стоимостей перевозок единицы товара введены некорректно. Исправьте ошибку и повторите попытку";
return;
}
x[i][j] = 0;
f[i][j] = 0;
}
}
double bal = 0;
for (int i = 0; i < m; i++)
{
bal += a[i];
}
for (int i = 0; i < n; i++)
{
bal -= b[i];
}
if (Math.Abs(bal)>0.0000000001)
{
X.Text = "Ошибка!\nЗадача несбалансирована. Исправьте ошибку (сбалансируйте задачу) и повторите попытку";
return;
}
List<Point> circle = new List<Point>();
int ai = 0, bj = 0, quanOfVar = 0;
double p;
double[] ta = a, tb = b;
do
{
p = Math.Min(ta[ai], tb[bj]);
ta[ai] -= p;
tb[bj] -= p;
x[ai][bj] = p;
f[ai][bj] = 1;
if (ta[ai] == 0)
{
ai++;
}
if (tb[bj] == 0)
{
bj++;
}
quanOfVar++;
}
while (ai <= m - 1 && bj <= n - 1);
quanOfVar = m + n - 1 - quanOfVar;
bool is1r1c;
for (int k = 0; k < quanOfVar; k++)
{
is1r1c = false;
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
if (f[i][j] == 0 && numof1(f, i, j))
{
is1r1c = true;
f[i][j] = 1;
}
if (is1r1c) break;
}
if (is1r1c) break;
}
}
bool isopt;
bool isNegative;
double[][] f1 = new double[f.Length][];
for (int i = 0; i < f.Length; i++)
{
f1[i] = new double[f[i].Length];
}
double mincount, cost;
int numofmatr = 0, numofc=0;
do
{
numofmatr++;
isopt = true;
isNegative = false;
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
equal(ref f1, f);
numofc++;
circle.Clear();
if (f[i][j] == 0)
{
circle.Add(new Point(i,j));
f1[i][j] = 2;
cost = 0;
bool err=circleOfEnumerizing(ref f1, 1, i, j, ref circle);
for (int k = 0; k < circle.Count; k++)
{
cost+=c[circle[k].GetX()][circle[k].GetY()] * Math.Pow(-1, k);
}
isNegative = (cost < 0);
}
if (isNegative) break;
}
if (isNegative) break;
}
if (isNegative)
{
mincount = x[circle[1].GetX()][circle[1].GetY()];
isopt = false;
for (int i = 1; i < circle.Count/2; i++)
{
mincount=(Math.Min(mincount, x[circle[2*i+1].GetX()][circle[2*i+1].GetY()]));
}
bool v = true;
f[circle[0].GetX()][circle[0].GetY()] = 1;
for (int i = 0; i < circle.Count; i++)
{
x[circle[i].GetX()][circle[i].GetY()]+=mincount*Math.Pow(-1,i);
if (x[circle[i].GetX()][circle[i].GetY()] == 0 && v && i%2==1)
{
f[circle[i].GetX()][circle[i].GetY()] = 0;
v = false;
}
}
}
}
while (!isopt);
double s = 0;
int maxstr = 0;
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
if (Convert.ToString(x[i][j]).Length > maxstr) maxstr = Convert.ToString(x[i][j]).Length;
}
}
maxstr += 1;
X.Text = "Количество итераций=" + Convert.ToString(numofmatr) + "\nКоличество посчитанных циклов=" + Convert.ToString(numofc) + "\n\nМатрица перевозок:\n\n";
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
for (int d = 0; d < maxstr - Convert.ToString(x[i][j]).Length; d++) X.Text += ' ';
X.Text += Convert.ToString(x[i][j]);
s += x[i][j]*c[i][j];
}
X.Text += '\n';
}
X.Text += "\nОбщая стоимость перевозки=" + Convert.ToString(s);
}
private void sc_Click(object sender, EventArgs e)
{
SaveFileDialog sfd = new SaveFileDialog();
sfd.Filter = "Текстовые Файлы(*.txt)|*.txt";
sfd.ShowDialog();
string s_f = sfd.FileName;
sfd.Dispose();
StreamWriter x;
try
{
x = new StreamWriter(s_f, false);
}
catch (Exception)
{
return;
}
x.WriteLine(C.Lines.Length);
for (int i = 0; i < C.Lines.Length; i++)
{
x.WriteLine(C.Lines[i]);
}
x.WriteLine(A.Lines.Length);
for (int i = 0; i < A.Lines.Length; i++)
{
x.WriteLine(A.Lines[i]);
}
x.WriteLine(B.Lines.Length);
for (int i = 0; i < B.Lines.Length; i++)
{
x.WriteLine(B.Lines[i]);
}
x.Close();
}
private void lc_Click(object sender, EventArgs e)
{
OpenFileDialog sfd = new OpenFileDialog();
sfd.Filter = "Текстовые Файлы(*.txt)|*.txt";
sfd.ShowDialog();
string s_f = sfd.FileName;
sfd.Dispose();
StreamReader x;
try
{
x = new StreamReader(s_f, false);
}
catch (ArgumentException)
{
return;
}
catch (FileNotFoundException)
{
X.Text = "Ошибка! Файл не найден";
return;
}
string tmp = x.ReadLine();
C.Text = "";
A.Text = "";
B.Text = "";
int n = 0;
try
{
n = Convert.ToInt16(tmp);
}
catch (Exception)
{
X.Text = "Ошибка чтения файла! Возможно файл не является архивом начальных условий программы. Попробуйте загрузить другой файл или ввести данные вручную!";
return;
}
tmp = "";
for (int i = 0; i < n; i++)
{
tmp += x.ReadLine();
if (i<n-1) tmp+="\n";
}
C.Text = tmp;
tmp = x.ReadLine();
try
{
n = Convert.ToInt16(tmp);
}
catch (Exception)
{
X.Text = "Ошибка чтения файла! Возможно файл не является архивом начальных условий программы. Попробуйте загрузить другой файл или ввести данные вручную!";
return;
}
tmp = "";
for (int i = 0; i < n; i++)
{
A.Text+= x.ReadLine();
if (i < n - 1) A.Text += "\n";
}
tmp = x.ReadLine();
try
{
n = Convert.ToInt16(tmp);
}
catch (Exception)
{
X.Text = "Ошибка чтения файла! Возможно файл не является архивом начальных условий программы. Попробуйте загрузить другой файл или ввести данные вручную!";
return;
}
tmp = "";
for (int i = 0; i < n; i++)
{
B.Text += x.ReadLine();
if (i < n - 1) B.Text += "\n";
}
x.Close();
}
private void sx_Click(object sender, EventArgs e)
{
SaveFileDialog sfd = new SaveFileDialog();
sfd.Filter = "Текстовые Файлы(*.txt)|*.txt";
sfd.ShowDialog();
string s_f = sfd.FileName;
sfd.Dispose();
StreamWriter x;
try
{
x = new StreamWriter(s_f, false);
}
catch (Exception)
{
return;
}
for (int i = 0; i < X.Lines.Length; i++)
{
x.WriteLine(X.Lines[i]);
}
x.Close();
}
}
}
