русс | укр

Языки программирования

ПаскальСиАссемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование

Все о программировании


Linux Unix Алгоритмические языки Аналоговые и гибридные вычислительные устройства Архитектура микроконтроллеров Введение в разработку распределенных информационных систем Введение в численные методы Дискретная математика Информационное обслуживание пользователей Информация и моделирование в управлении производством Компьютерная графика Математическое и компьютерное моделирование Моделирование Нейрокомпьютеры Проектирование программ диагностики компьютерных систем и сетей Проектирование системных программ Системы счисления Теория статистики Теория оптимизации Уроки AutoCAD 3D Уроки базы данных Access Уроки Orcad Цифровые автоматы Шпаргалки по компьютеру Шпаргалки по программированию Экспертные системы Элементы теории информации

Табулирование функции одного аргумента с выбором расчетной формулы.


Дата добавления: 2013-12-23; просмотров: 1317; Нарушение авторских прав


Задача оптимального выбора

Else

Begin

Var

Repeat

Begin

инициализировать выбор позиции для i-того ферзя;

выбор позиции

if безопасно then begin

поставить ферзя;

if i<8 then begin

Attemt(i+1);

if неудача then снять ферзя

end;

end;

until удачно or больше позиций нет

end;

По шахматным правилам ферзь бьет все фигуры, расположенные на той же вертикали, горизонтали и диагонали. Поскольку каждая вертикаль может содержать только одного ферзя, i-того ферзя можно сразу же помещать на i-тую вертикаль. Параметр i становится индексом вертикали, а выбор позиции ограничивается восемью возможными значениями индекса горизонтали j.

Теперь необходимо выбрать представление шахматной доски. Первое, что приходит на ум — массив 8×8. Однако при выборе позиции для постановки очередного ферзя необходимо проверять, свободны ли соответствующие диагонали и горизонталь, а при таком представлении доски эта проверка будет сложной и громоздкой. Поэтому позиции ферзей имеет смысл записывать в одномерном массиве, где индекс массива — номер вертикали, а значение — номер горизонтали. Введем еще три одномерных массива логического типа, содержащих сведения о занятости каким-либо ферзем горизонтали и двух диагоналей. Поскольку для всех полей главной диагонали и всех параллельных ей постоянна разность координат ij, а для побочной диагонали (и всех параллельных ей) постоянна сумма i + j , а также учитывая значения суммы и разности индексов для соответствующих диагоналей, представление шахматной доски будет следующим:

const

SizeCB = 8; // размер шахматной доски

PosQ : array[1..SizeCB] of integer;

NoHor : array[1..SizeCB] of Boolean;

NoRDiag: array[2..2*SizeCB] of Boolean;



NoLDiag: array[-SizeCB+1..SizeCB-1] of Boolean;

где

o PosQ[i]указывает позицию ферзя на i-той вертикали;

o NoHor[j] означает отсутствие ферзя на j-той горизонтали;

o NoRDiag[k] означает отсутствие ферзя k-той "побочной" диагонали;

o NoLDiag[k] означает отсутствие ферзя k-той"главной" диагонали.

Выход из рекурсии осуществляется по достижению одного из условий: решение найдено или все варианты испробованы. Поэтому среди параметров процедуры расстановки ферзей присутствует параметр, свидетельствующий о найденности решения. Процедура представлена в листинге 10.10.

Листинг 10.10. Восемь ферзей. Один вариант

procedure Queen(i: integer; var found: Boolean);

var

j: integer; // индекс горизонтали

l: integer;

begin

j:=0;

repeat

inc(j); found:=false;

for l:=1 to SizeCB do queens.Form1.DrawQueen(i+1,l,' ');

if NoHor[j] and NoRDiag[i+j] and NoLDiag[i-j] then begin

// если безопасно

PosQ[i]:=j; // поставить ферзя

NoHor[j]:= false; // j-ая горизонталь занята

NoRDiag[i+j]:=false; // побочная диагональ занята

NoLDiag[i-j]:=false; // главная диагональ занята

queens.Form1.DrawQueen(i,j,'Y'); // нарисовать ферзя

Sleep(100); Application.ProcessMessages;

if i< SizeCB then begin

Queen(i+1,found);

if not found then begin // снять ферзя

NoHor[j]:= true; // j-ая горизонталь свободна

NoRDiag[i+j]:=true; //побочная диагональ свободна

NoLDiag[i-j]:=true; //главная диагональ свободна

queens.Form1.DrawQueen(i,j,'*'); // стереть ферзя

Sleep(500); Application.ProcessMessages;

end

end

else begin

found:=true;

queens.Form1.DrawQueen(i,j,'Y'); // нарисовать ферзя

Sleep(100); Application.ProcessMessages;

end;

end

until found or (j=SizeCB);

end;

Создадим проект, форма которого представлена на рис. 10.6. На форме отражена ситуация, когда ферзи уже расставлены. Крестиком отмечены позиции ферзей на предыдущих уровнях рекурсии, приводящие к тупиковому случаю.

Рис. 10.6. Форма проекта Восемь ферзей (один вариант)

На форме выставлены два компонента:

o компонент StringGrid;

o кнопка Расставить.

Обработчик события Click кнопки Расставить освобождает все горизонтали и диагонали шахматной доски и вызывает процедуру расстановки ферзей Queen:

Листинг 10.11. Восемь ферзей. Расстановка ферзей

procedure TForm1.BtnTryClick(Sender: TObject);

var

i: integer;

begin

for i:=1 to SizeCB do NoHor[i]:= true; // горизонтали свободны

for i:=2 to 2*SizeCB do NoRDiag[i]:=true; //все "побочные"

// диагонали свободны

for i:=-SizeCB+1 to SizeCB-1 do NolDiag[i]:=true;

// все "главные" диагонали свободны

Queen(1,ok);

end;

Заполнение доски фигурами происходит в два этапа. Сначала в ячейки StringGrid процедура Queen вносит информацию о положении ферзей: поставленного или снятого (см. листинг 10.10), вызывая процедуру DrawQueen:

procedure TForm1.DrawQueen(d,l: integer; fig: char);

begin

with StrGrd do begin

Cells[d-1,l-1]:=fig;

end;

end;

а потом идет рисование шахматной доски с использованием заранее подготовленных рисунков в формате .bmp:

procedure TForm1.StrGrdDrawCell(Sender: TObject; ACol, ARow: Integer;

Rect: TRect; State: TGridDrawState);

begin

with StrGrd.Canvas do begin

if not odd(ACol+ARow) then Brush.Color:=clWhite

else Brush.Color:=clSilver;

FillRect(Rect);

if StrGrd.Cells[ACol,ARow]='Y' then

Draw(Rect.Left,Rect.Top,BmpQueen)

else

if StrGrd.Cells[ACol,ARow]='*' then

Draw(Rect.Left,Rect.Top,QEmpty);

end;

end;

 

Важное обобщение задачи проб и ошибок — находить не одно, а все решения поставленной задачи. В случае задачи о восьми ферзяхтребуется найти все возможные расстановки ферзей на шахматной доске. Общая схема данного алгоритма получается из схемы, приведенной в листинге 10.9.

procedure Attemt(i: integer);

k: integer;

for k:=1 to m do begin

выбор k-того возможного хода

if ход удачен then begin

записать ход;

if i<n then

Attemt(i+1)

нарисовать очередную расстановку ферзей ;

стереть ход;

end;

end;

end;

Так как условие окончания цикла зависит только от одной переменной, то цикл repeat заменен на цикл for и процедура содержит только один параметр. Таким образом, поиск всех возможных решений представляется более простой программой, чем поиск только одного решения. Этот алгоритм приведен в листинге 11.12.

Листинг 10.12. Восемь ферзей. Все варианты

procedure Queen8All (i: integer);

var

j: integer; // индекс горизонтали

begin

for j:=1 to SizeCB do

if NoHor[j] and NoRDiag[i+j] and NoLDiag[i-j] then begin

// нет ферзя на соотв. горизонтали и диагоналях

PosQ[i]:=j;

NoHor[j]:= false; // j-ая горизонталь занята

NoRDiag[i+j]:=false; // побочная диагональ занята

NoLDiag[i-j]:=false; // главная диагональ занята

if i< SizeCB then Queen8All(i+1)

else begin

queenall.Form1.DrawQueen{(i,j,'Y')}; // поставить ферзя

Sleep(1000); Application.ProcessMessages;

end;

NoHor[j]:= true; // j-ая горизонталь опять свободна

NoRDiag[i+j]:=true; // побочная диагональ опять свободна

NoLDiag[i-j]:=true; // главная диагональ опять свободна

end

end;

Форма проекта для всех возможных расстановок ферзей показана на рис. 10.7. Из всех возможных расстановок показана последняя. В этом проекте позиции ферзей на предыдущих уровнях рекурсии не указываются.

Рис. 10.7. Восемь ферзей. Все варианты

Компоненты на форме проекта те же, что и на предыдущей форме (рис. 10.6). Обработчик события Click кнопки Расставить вызывает, после инициализации доски, процедуру Queen8All, приведенную в листинге 10.11.

Всего возможны 92 расстановки, из них только 12 принципиально различных. Остальные получаются с помощью осевой или центральной симметрий.

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

Для этого необходимо получить все возможные решения, и в процессе их получения оставлять только то, которое наилучшим образом удовлетворяет условию. Такой подход аналогичен поиску максимального элемента в последовательности: каждый последующий элемент последовательности сравнивается с максимальным из предыдущих — "локальным" максимумом, и при необходимости этот локальный максимум переприсваивается.

В качестве примера задачи оптимального выбора решим такую. Пусть есть некоторое количество предметов, характеризующихся двумя величинами: весом и ценой. Требуется найти оптимальную выборку, то есть выбрать предметы, имеющие наибольшую суммарную стоимость при предельном общем весе. Такие задачи приходится решать, собираясь в путешествие и упаковывая чемоданы или (шутка!) при ограблении ювелирного магазина.

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

Данные, необходимые для решения этой задачи, опишем следующим образом:

const

N=15; // количество предметов

type

TItem=record // предмет

weight: integer; // вес

cost : integer; // цена

end;

index = 1..N;

var

a: array[index] of TItem;

MaxCst, // наибольшая стоимость выборки

LimWeight, // предельный вес выборки

TotC : integer; // полная стоимость

i: index;

s, sOpt : set of index; // текущая и оптимальная выборки

В листинге 10.13 приведена процедура TryOpt, которая формирует оптимальную выборку. В этой процедуре исследуется целесообразность включения в выборку каждого предмета, она рекурсивно вызывается при переходе к следующему предмету до тех пор, пока все предметы не будут рассмотрены.

Листинг 10.13. Оптимальный выбор

procedure TryOpt(i: index; pWeight,pCost: integer);

var

tmp : integer;

begin

// попытка включить i-тый предмет, ограничение: вес

if pWeight + a[i].weight <= LimWeight then begin

s:=s+[i]; // включение в выборку

if i<N then TryOpt(i+1,pWeight+a[i].weight,pCost)

else

if pCost > MaxCst then begin

MaxCst:=pCost; // запоминание локального максисума

sOpt:=s // запоминание выборки

end;

s:=s-[i];

end;

tmp:=pCost - a[i].cost;

// попытка исключить предмет i, ограничение: стоимость

if tmp>MaxCst then begin

if i<N then TryOpt(i+1,pWeight,tmp)

else begin

MaxCst:=tmp; sOpt:=s; // запоминание выборки

end;

end;

end;

Форма проекта, иллюстрирующего нахождение оптимальной выборки, представлена на рис. 10.8.

Рис. 10.8. Оптимальный выбор

На форме выставлены компоненты:

o компонент StringGrid, две верхние строки которого содержат вес и цену предметов, а в нижней отмечены предметы, включенные в оптимальную выборку;

o кнопка Заполнить случайным образом,

o компонент Edit, предназначенный для ввода значения предельного веса;

o кнопка Найти оптимум, инициирующая необходимые переменные и вызывающая процедуру TryOpt .

Обработчик события Click кнопки Найти оптимум представлен в листинге 10.14.

Листинг 10.14. Оптимальный выбор. Обработчик события Click кнопки Найти оптимум

procedure TForm1.BtnExeClick(Sender: TObject);

var i: index;

begin

TotC:=0;

for i:=1 to N do

with SGSel do begin

a[i].weight:=StrToInt(Cells[i,0]); // обновление

a[i].cost:=StrToInt(Cells[i,1]); // массива

TotC:=TotC+StrToInt(Cells[i,1]); // вычисление полной

// стоимости предметов

Cells[i,2]:='';

end;

LimWeight:=StrToInt(EdtIn.Text); // считывание предельного веса

MaxCst:=0; s:=[]; sOpt:=[]; // инициализация

TryOpt(1,0,TotC); // вызов процедуры, находящей оптимальную выборку

end;

Необходимость обновления массива a связана с тем, что задавать характеристики предметов можно любым из способов:

o ввод вручную;

o случайными значениями (кнопка Заполнить случайным образом);

o замена любых значений в нужных ячейках после случайного заполнения.

В заключение необходимо заметить, что если бы решать задачу без рекурсии, то пришлось бы вычислить вес и стоимость всех возможных выборок, а число выборок для 15 предметов 215 – 1 = 32767. Ограничения, используемые в процедуре TryOpt, позволяют сократить число операций при нахождении оптимальной выборки, до £ 2000. Число рекурсивных вызовов процедуры TryOpt не превышает » 500.

 

Лекция 2. 1

Очереди. 1

9.3.1. Динамическая реализация очереди. 2

9.3.2. Очередь, реализованная с помощью массива. 5

Рекурсия. 10

10.4. Алгоритмы с возвратом.. 10

10.4.1. Расстановка ферзей. 11

10.4.2. Задача оптимального выбора. 17

 

Пример. Протабулировать функцию Z.

 
 


 
 


Z=
где t Î [-1, 1] c да

шагом Dt = 0,2

a = 2,1 нет

Z = at + b
b = 0,37 да

       
   


нет

 
 

 

 




<== предыдущая лекция | следующая лекция ==>
Расстановка ферзей | Конспект лекций


Карта сайта Карта сайта укр


Уроки php mysql Программирование

Онлайн система счисления Калькулятор онлайн обычный Инженерный калькулятор онлайн Замена русских букв на английские для вебмастеров Замена русских букв на английские

Аппаратное и программное обеспечение Графика и компьютерная сфера Интегрированная геоинформационная система Интернет Компьютер Комплектующие компьютера Лекции Методы и средства измерений неэлектрических величин Обслуживание компьютерных и периферийных устройств Операционные системы Параллельное программирование Проектирование электронных средств Периферийные устройства Полезные ресурсы для программистов Программы для программистов Статьи для программистов Cтруктура и организация данных


 


Не нашли то, что искали? Google вам в помощь!

 
 

© life-prog.ru При использовании материалов прямая ссылка на сайт обязательна.

Генерация страницы за: 0.178 сек.