Тезей должен был найти выход из Критского лабиринта или погибнуть, убитый Минотавром. Но что поразительно: найти вход в лабиринт - задача не менее трудная.
Здесь не представляется возможным описать все мыслимые лабиринты, да это и не требуется. Мы займемся простыми лабиринтами, построенными на прямоугольнике $$m\times n$$, где $$m,n$$ — положительные целые числа. Внутри и на границах прямоугольника поставлены стенки по ребрам покрывающей его единичной квадратной сетки. Чтобы построить из прямоугольника лабиринт, выбьем одну единичную стенку на одной из сторон прямоугольника (получится вход в лабиринт); выбьем одну единичную стенку на противоположной стороне (получится выход) и еще удалим какое-то число строго внутренних стенок. Говорят, что лабиринт имеет решение, если между входом и выходом внутри лабиринта есть путь в виде ломаной, не имеющей общих точек со стенками. Решение единственно, если любые два таких пути проходят через одни и те же внутренние ячейки сетки. На рис. 17.1 приведен пример лабиринта $$5\times 5$$.
(рис 17.1) Пример лабиринтаОдин из возможных подходов к решению таков. Выбираем вход; затем, начав от него, добавляем по одной ячейке к главному пути-решению, пока он не достигнет выходной стороны. После этого удаляем некоторые внутренние стенки так, чтобы все клетки оказались соединенными с главным путем. Чтобы главный путь не получился прямым коридором, следует при его построении предусмотреть случайные повороты. Программа должна также следить за тем, чтобы при построении главного пути или при открытии боковых ячеек не нарушалась единственность решения. Наблюдательный читатель заметит, что определение единственности решения не годится в случае, когда путь заходит в боковой тупик и затем возвращается.
Программу можно написать почти на любом из процедурных языков.
Программа 1. Лабиринт.
{Программно задаются вход и выход. Нажимая на клавишу "Enter",
перебираем всевозможные пути от входа до выхода в лабиринте.
Выход из программы по клавише "Esc".
Алгоритм реализован на языке программирования Turbo-Pascal}
program Maze;
uses
Graph, Crt;
var
m,n: Integer;
Matrix: array [1..100,1..100] of Boolean;
Start,Finish: Integer;
procedure PrepareGraph;
var
Driver,Mode: Integer;
begin
Driver:=VGA;
Mode:=VGAHi;
InitGraph(Driver,Mode,'c:\borland\tp\bgi');
end;
procedure DisplayMaze(x1,y1,x2,y2: Integer);
var
i,j: Integer;
dx,dy: Real;
begin
SetFillStyle(1,8);
SetColor(15);
dx:=(x2-x1)/m;
dy:=(y2-y1)/n;
for i:=1 to n do
for j:=1 to m do
if not Matrix[i,j] then
Rectangle(Round(x1+(i-1)*dx),Round(y1+(j-1)*dy),
Round(x1+i*dx),Round(y1+j*dy));
end;
function CreatesPath(i,j: Integer): Boolean;
var
Result: Boolean;
Count: Integer;
ii,jj: Integer;
begin
Count:=0;
if (i>1) and Matrix[i-1,j] then Inc(Count);
if (i<m) and Matrix[i+1,j] then Inc(Count);
if (j>1) and Matrix[i,j-1] then Inc(Count);
if (j<m) and Matrix[i,j+1] then Inc(Count);
if Count>1 then Result:=true else Result:=false;
CreatesPath:=Result;
end;
function DeadEnd(i,j: Integer): Boolean;
var
Result: Boolean;
Count: Integer;
begin
Count:=0;
if (i=2) or CreatesPath(i-1,j) then Inc(Count);
if (i=m-1) or CreatesPath(i+1,j) then Inc(Count);
if (j=2) or CreatesPath(i,j-1) then Inc(Count);
if (j=n-1) or CreatesPath(i,j+1) then Inc(Count);
if Count=4 then Result:=true else Result:=false;
DeadEnd:=Result;
end;
function CreateMaze: Boolean;
var
i,j: Integer;
di,dj: Integer;
Result: Boolean;
begin
Randomize;
for i:=1 to n do
for j:=1 to m do Matrix[i,j]:=false;
Start:=Random(m-2)+2;
i:=Start;
j:=2;
Matrix[Start,1]:=true;
repeat
Matrix[i,j]:=true;
di:=0;
dj:=0;
while (di=0) and (dj=0) do begin
di:=1-Random(3);
if (i+di=1) or (i+di=m) then di:=0;
if di=0 then dj:=1-Random(3);
if j+dj=1 then dj:=0;
if CreatesPath(i+di,j+dj) then begin
di:=0;
dj:=0;
end;
end;
i:=i+di;
j:=j+dj;
until DeadEnd(i,j) or (j=n);
Finish:=i;
Matrix[Finish,n]:=true;
if j<n then Result:=false else Result:=true;
CreateMaze:=Result;
end;
begin
m:=6;
n:=6;
PrepareGraph;
repeat
ClearDevice;
repeat until CreateMaze;
DisplayMaze(120,40,520,440);
repeat until KeyPressed;
until ReadKey=#27;
CloseGraph;
end.
Программа 2. Лабиринт.
{Лабиринт реализуется автоматически, без участия пользователя.
Алгоритм реализован на языке программирования Turbo-Pascal }
uses graph,crt;
var
mpos,npos,m,n,delx,x,y,t,gd,gm,i,k:integer;
begin
randomize;
writeln('Input labyrint size (x and y)');
readln(m,n);
writeln('Input entranceexit coordinates (mpos<m and npos<m)');
readln(mpos,npos);
initgraph(gd,gm,'c:\borland\tp\bgi');
for i:=1 to m do
begin
for k:=1 to n do
begin
rectangle(90+10*i,90+10*k,90+10*i+10,90+10*k+10);
end;
end;
setfillstyle(1,0);
setcolor(0);
line(100+(mpos-1)*10+1,100,100+(mpos-1)*10+9,100);
line(100+(npos-1)*10+1,100+n*10,100+(npos-1)*10+9,100+n*10);
y:=n;
x:=npos;
readln;
while y>1 do
begin
delx:=random(m)-x+1;
if y=2 then delx:=mpos-x;
i:=91+x*10;
if i<90+(x+delx)*10 then
begin
while i<>90+(x+delx)*10 do
begin
i:=i+1;
line(i,91+y*10,i,99+y*10);
end;
end;
if i>91+(x+delx)*10 then
begin
while i<>91+(x+delx)*10 do
begin
i:=i-1;
line(i,91+y*10,i,99+y*10);
end;
end;
x:=x+delx;
line(91+10*x,90+y*10,99+10*x,90+y*10);
y:=y-1;
end;
readln;
end.
Строится бинарное дерево. В узлы дерева засылаются целые положительные числа, выбранные случайным образом. После задания значений вершин на каждом уровне эти значения выводятся на экран, начиная с корневой. Пользователю предлагается сделать выбор номера уровня, в нем определяется максимальное значение и выводится на экран.
Программа 3. Поиск максимального элемента.
{ Алгоритм реализован на языке программирования Turbo-Pascal}
uses crt;
type sp=^tree;
tree=record
val:integer;
l:sp;
r:sp;
end;
var
t:sp;
nh, max,h,i:integer;
procedure find(t:sp; h,nh:integer);
begin
if t=nil then exit;
if h=nh then
begin
if t^.val> max then max:=t^.val;
end
else
begin
find(t^.l,h+1,nh);
find(t^.r,h+1,nh);
end;
end;
procedure zadtree(var t:sp; h,nh:integer);
begin
if h=5 then
begin
new(t);
t^.l:=nil;
t^.r:=nil;
t^.val:=random(100);
end
else
begin
new(t);
zadtree(t^.l, h+1,nh);
zadtree(t^.r, h+1,nh);
t^.val:=random(100);
end;
end;
procedure writetree(t:sp; h,nh:integer);
begin
if t=nil then exit;
if h=nh then
begin
write(t^.val,' ');
end
else
begin
writetree(t^.l,h+1,nh);
writetree(t^.r,h+1,nh);
end;
end;
begin
clrscr;
randomize;
t:=nil;
zadtree(t,1,nh);
for i:=1 to 5 do
begin
writetree(t,1,i);
writeln;
end;
max:=0;
write('vvedite uroven ');
readln(nh);
find(t,1,nh);
write('max= ',max);
readln;
end.
Условие задачи. Найти все такие расстановки восьми ферзей на шахматной доске, при которых ферзи не бьют друг друга.
Анализ задачи. Пусть $$A$$ - множество искомых расстановок (конфигураций). Рассмотрим следующий подход к решению задачи. Будем искать множество конфигураций $$B$$ со следующими свойствами:
С помощью процедуры из пункта 3 будем генерировать по очереди все элементы из $$B$$ ; для элементов из $$B$$ проверяем (см. пункт 2) принадлежит ли он $$A$$: в результате в силу 1 свойства будут порождены все элементы $$A$$.
Заметим теперь, что ферзи, которые не бьют друг друга, должны располагаться на разных горизонталях. Поэтому можно упорядочить ферзи и всегда ставить $$k$$ -го ферзя на $$k$$ -ю горизонталь. Тогда в качестве $$B$$ можно взять множество конфигураций, в которых на каждой из первых $$N$$ горизонталей стоит ровно по одному ферзю, причем никакие два ферзя не бьют друг друга.
Программа 4. Расстановка восьми ферзей на шахматной доске.
{ Программа выдает все комбинации ферзей, которые не бьют друг друга.
Алгоритм реализован на языке программирования Turbo-Pascal }
program ferz;
uses crt;
const desksize=8;
type sizeint=1..desksize;
unuses=set of sizeint;
combinates=array[shortint] of sizeint;
var num:byte;
combinate:combinates;
unuse:unuses;
function attack(combinate:combinates):boolean;
var i,j:byte;
rightdiag,leftdiag:combinates;
begin
attack:=false;
for i:=1 to desksize do
begin
leftdiag[i]:=i+combinate[i];
rightdiag[i]:=i-combinate[i];
end;
for j:=1 to desksize do
for i:=1 to desksize do
begin
if (i<>j) and ((leftdiag[i]=leftdiag[j])or(rightdiag[i]=rightdiag[j]))
then
begin
attack:=true;
exit;
end;
end;
end;
procedure output(combinate:combinates);
var i,j:byte;
begin
for i:=1 to desksize do
for j:=1 to desksize do
begin
gotoxy(i,j);
if(combinate[i]=j) then write(#2) else write(' ');
end;
readln;
end;
procedure create(num:byte; unuse:unuses; combinate:combinates);
var i:byte;
begin
if num<=desksize then
for i:=1 to desksize do
begin
if i in unuse then
begin
combinate[num]:=i;
create(num+1,unuse-[i],combinate);
end;
end
else if not attack(combinate) then output(combinate);
end;
begin
textmode(c40);
clrscr;
unuse:=[1..desksize];
create(1,unuse,combinate);
end.
В лекциях 14 и 15 мы рассматривали более подробно различные способы сортировки. Здесь мы напоминаем некоторые из них и приводим пример программ.
Сортировка по возрастанию - это сортировка, при которой записи упорядочиваются по возрастанию значений ключевых полей.
Сортировка по убыванию - это сортировка, при которой записи упорядочиваются по убыванию значений ключевых полей.
Сортировка методом пузырька (
Сортировка по ключу - это сортировка записей с упорядочением по значению указанного поля или группы полей.
Сортировка слиянием - это
Сортировка Батчера - это сортировка, внутренний алгоритм которой работает за время $$O(N\cdot\log (N))$$.
Программа 5. Сортировка массива по возрастанию методом пузырька.
//Данные, которые нужно отсортировать, берутся из файла "massiv.txt",
//результат записывается в массив int mas['K'] и выводится на экран
// Алгоритм реализован на Turbo C++.
#include <conio.h>
#include <stdio.h>
#define K 1000; //Размер массива
int mas['K'];
int n;
void puzirek()//функция сортирует массив по возрастанию методом пузырька
{
int i,j,t;
for(i=0;i<n;i++)
for(j=1;j<n-i;j++)
if(mas[j]<mas[j-1])
{
t=mas[j];
mas[j]=mas[j-1];
mas[j-1]=t;
}
}
int main()
{
clrscr();
FILE *filePointer=fopen("massiv.txt","r");
int i=0;
while (!feof(filePointer))
{
fscanf(filePointer,"%d",mas[i]);
i++;
}
n=i;
puzirek();
for(i=0;i<n;i++)
printf("%d ",mas[i]);
//scanf("%d",n);
getch();
return 0;
}
Программа 6. Пузырьковая сортировка и сортировка методом прямого выбора.
{Сортировка. Алгоритм реализован на языке программирования Turbo-Pascal}
uses crt;
var
M, N : array[0..10] of integer;
i:integer;
procedure Input;
begin
for i := 0 to 10 do
begin
writeln('Число');
readln(M[i]); {Ввод массива}
end;
end;
Procedure Sort1; {Пузырьковый метод сортировки}
var
q,i,x:integer;
begin
for i:=10 downto 0 do
begin
for q:=0 to 10 do
if M[q]<M[q+1] then
begin
x:=M[q];
M[q]:=M[q+1];
M[q+1]:=x
end;
end;
end;
procedure Sort2; {Метод прямого выбора}
var
i,j,k,x:integer;
begin
for i:=0 to 9 do
begin
k:=i;
x:=M[i];
for j:=i+1 to 10 do
if M[j] >x then begin k:=j; x:=M[k];
end;
M[k]:= M[i];
M[i]:=x;
end;
end;
{---------------------------------------------}
begin
clrscr;
input; {Ввод исходного массива}
writeln('Исходный массив');
for i:=0 to 10 do write(M[i],' '); {Вывод исходного массива}
writeln;
Sort1;{Сортировка массива методом пузырька}
writeln ('Сортированный массив');
for i:=0 to 10 do write(M[i],' '); {Вывод отсортированного массива}
input; {Ввод исходного массива}
writeln('Исходный массив');
for i:=0 to 10 do write(M[i],' '); {Вывод исходного массива}
writeln;
sort2;
writeln ('Сортированный массив методом прямого выбора');
for i:=0 to 10 do write(M[i],' '); {Вывод отсортированного массива}
readln;
end.
Программа 7. Сестры.
//Две строки матрицы назовем сестрами, если совпадают
//множества чисел, встречающихся в этих строках. Программа
//определяет всех сестер матрицы, если они есть,
//и выводит номера строк. Алгоритм реализован на Turbo C++.
//#include <graphics.h>
#include <stdlib.h>
//#include <string.h>
#include <stdio.h>
#include <conio.h>
//#include <math.h>
#include <dos.h>
#include <values.h>
#include <iostream.h>
const n=4,//кол-во строк
m=4; //столбцов
int m1[n][m];
//исходный массив
struct mas{int i,i1;};
//i-индекс сравниваемой строки с i1 строкой
mas a[n*2];
//массив типа mas, где будут лежать сестры, пример) a[1].i и a[1].i1 -
сестры
void main()
{clrscr();
int i,j;
randomize();
for( i=0;i<n;i++)
for( j=0;j<m;j++)
m1[i][j]=random(2);
//случайным образом в массив заносим цифры
for(i=0;i<n;i++)
{printf("\n %d) ",i);
for(int j=0;j<m;j++)
printf(" %d",m1[i][j]);
//распечатываем этот массив
}
int min,
p;
//индекс минимального элемента после s-го элемента i-ой строки
//сортировка строк массива по возрастанию
for(i=0;i<n;i++)//i-сортировка i-ой строки
{
for(int s=0;s<m-1;s++)
{min=m1[i][s+1];
for(int j=s;j<m;j++)
if(m1[i][j]<=min){min=m1[i][j];p=j;}
//запоминаем минимальный элемент в ряде после s-го элемента
if(m1[i][s]>=min)
{m1[i][p]=m1[i][s];m1[i][s]=min;}
//меняем местами s-й и p-й элемент,если s-й>p-го(минимального)
}
}
printf("\n");
for(i=0;i<n;i++)
{printf("\n %d) ",i);
for(int j=0;j<m;j++)
printf(" %d",m1[i][j]);
//выводим отсортированный массив
}
int s=0 //сколько элементов в i-й строке совпадают с
эл-ми i1 строки, k=0;
//сколько строк совпали
int i1;
for(i=0;i<n-1;i++) //верхняя строка i
for( i1=i+1;i1<n;i1++) //нижняя строка i1
{s=0;
for(int j=0;j<m;j++)
//сравнение идет по j-му столбцу
// ! !
if(m1[i][j]==m1[i1][j])s++; //если соответствующие элементы в
//i-й и i1-й строки совпадают, то кол-во совпавших увеличивается на 1
if(s==m){a[k].i=i;a[k].i1=i1;k++;}
//если все элементы i-й и i1-й строки совпали, то они сестры
}
printf("\nСестры :");
for(i=0;i<k;i++)
printf("\n %d и %d",a[i].i,a[i].i1);
//распечатываем a[i].i-ю и a[i].i1-ю сестру
getch();
}
Программа 8. Поиск узоров из простых чисел.
//Построить матрицу А(15 Х 15)таким образом: А(8,8)=1, затем
//по спирали против часовой стрелки,
//увеличивая значение очередного элемента на единицу
//и выделяя все простые числа красным цветом, заполнить матрицу
//Алгоритм реализован на Turbo C++.
#include <stdio.h>
#include <conio.h>
void main(void)
{
clrscr();
int mas[15][15];
int n=1,x=6,y=6,k=1;
int i,j;
while(1){
mas[x][y]=k++;
switch(n){
case 1: x++;break;
case 2: y--;break;
case 3: x--;break;
case 4: y++;break;
}
if(x==15) break;
if(x==y x<6) n=4;
else if(x+y==12 x<6) n=1;
else if(x+y==12 x>6) n=3;
else if(x==y+1 x>6) n=2;
}
for(i=0;i<15;i++)
{
for(j=0;j<15;j++)
{
textcolor(12);
if(mas[j][i]>2)
for(k=2;k<mas[j][i];k++)
if(mas[j][i]%k==0) textcolor(15);
cprintf("%3d ",mas[j][i]);
}
printf("\n");
}
getch();
}
Программа 9. Сортировка строк матрицы.
//Cортировка строк матрицы. В каждой строке подсчитывается сумма
//простых чисел. Полученный вектор упорядочивается по возрастанию.
//Строки матрицы переставляются по новому вектору.
//Алгоритм реализован на Turbo C++.
#include<stdio.h>
#include<conio.h>
#define n 5
struct summa
{
int value;
int idx;
} sum,massum[n],a;
void main(void){
clrscr();
int mas1[n][n],mas[n][n]={{1,1,1,1,1},
{3,16,11,6,4},
{8,10,15,23,1},
{3,8,10,15,3},
{7,3,20,15,10}};
int i,j,k,flag;
for(i=0;i<n;i++){
sum.value=0;
for(j=0;j<n;j++){
flag=0;
if(mas[i][j]>2)
for(k=2;k<mas[i][j];k++)
if(mas[i][j]%k==0) flag=1;
if(flag==0) sum.value=sum.value+mas[i][j];
}
sum.idx=i;
massum[i]=sum;
}
for(i=0;i<n-1;i++)
for(j=0;j<n-1-i;j++){
if (massum[j].value>massum[j+1].value){
a=massum[j];
massum[j]=massum[j+1];
massum[j+1]=a;
}
}
for(i=0;i<n;i++)
for(j=0;j<n;j++)
mas1[i][j]=mas[massum[i].idx][j];
for(i=0;i<n;i++){
for(j=0;j<n;j++)
printf("%3d ",mas[i][j]);
printf("\n");
}
printf("\n\n\n");
for(i=0;i<n;i++){
for(j=0;j<n;j++)
printf("%3d ",mas1[i][j]);
printf("\n");
}
getch();
}
Эта задача состоит в следующем. Пусть имеется $$n$$ работ и $$n$$ кандидатов для выполнения этих работ. Назначение кандидата $$i$$ на работу $$j$$ связано с затратами $$c_{ij}$$ $$(i,j=1,2,\ldots,n)$$. Требуется найти назначение кандидатов на все работы, дающее минимальные суммарные затраты; при этом каждого кандидата можно назначить только на одну работу и каждая работа может быть занята только одним кандидатом.
Иначе говоря, решение этой задачи представляет собой перестановку ( $$p_1,p_2,\ldots,p_n$$ ) чисел $$(1, 2, \ldots, n)$$ ; каждое из производимых назначений описывается соответствием $$i\to p_i$$ ( $$i=1,\ldots,n$$ ). Указанные условия единственности при этом автоматически выполняются, и нашей целью является минимизация суммы$$\sum_{i=1}^n c_{ip_i}$$ по всем перестановкам ( $$p_1,p_2,\ldots,p_n$$ ).
Перед нами типичная экстремальная комбинаторная задача. Ее решение путем прямого перебора, то есть вычисления значений функции 17.1 на всех перестановках и сравнения, практически невозможно при сколько-нибудь больших $$n$$, поскольку число перестановок равно $$n!=1\cdot 2\cdot 3\cdots (n-1)n$$. Попытаемся свести дело к линейному программированию.
Конечное множество, на котором задана целевая функция 17.1, представляет собой множество всех перестановок чисел $$(1, 2, \ldots, n)$$. Как известно, каждая такая перестановка может быть описана точкой в $$n^2$$ -мерном евклидовом пространстве; эту точку удобнее всего представить в виде $$n\times n$$ -матрицы $$X=\|x_{ij}\|$$. Элементы $$x_{ij}$$ интерпретировать следующим образом:
$$x_{ij}=1$$, если i-й кандидат назначается на j-ю работу,
$$x_{ij}=0$$, в противном случае.
Элементы матрицы должны быть подчинены двум условиям:$$\sum_{j=1}^{n}x_{ij}=1,\quad i=1,2,\ldots, n,$$ $$\sum_{i=1}^{n}x_{ij}=1,\quad j=1,2,\ldots, n.$$ Условия 17.3 и 17.4 говорят о том, что в каждой строке и в каждом столбце матрицы $$X$$ имеется ровно по одной единице. Говоря неформально, условие 17.3 означает, что каждый кандидат может быть назначен только на одну работу, а условие 17.4 — что каждая работа предназначена только для одного кандидата. (Матрицу перестановок можно получить из единичной матрицы путем некоторой перестановки ее строк.)
Теперь задача заключается в нахождении чисел $$x_{ij}$$, удовлетворяющих условиям 17.2, 17.3, 17.4 и минимизирующих суммарные затраты 17.1, которые теперь можно переписать в виде$$\sum_{i=1}^{n}\sum_{j=1}^nc_{ij}x_{ij}.$$ Казалось бы, что к полученной задаче методы линейного программирования непосредственно применить нельзя, ибо в силу условий 17.2 она формально является целочисленной. Заменим условие 17.2 на условие неотрицательности переменных$$x_{ij}>0.$$ Тем самым мы получаем обычную задачу линейного программирования. В нашем случае требование целочисленности 17.2 будет выполняться автоматически.
Программа 10.Назначение на работу.
program one;{Назначение на работу.
Рассматривается случай: 10 работ и 10 желающих.
реализовано на Turbo-Pascal}
uses crt;
const n=10;
var C : array [1..n,1..n] of integer;
T : array [1..n] of integer;
M : array [1..n,1..4] of integer;
Sum,tmj,z,min,i,j,tmp:integer;
begin
clrscr;
randomize;
write('work - ');
for i:=1 to n do write(i:2,' ');
for i:=1 to n do begin
writeln;
write(i:2,' man ');
for j:=1 to n do begin
C[i,j]:=random(100);
{if M[i,j]>max then max:=M[i,j];}
{if C[i,j]<min then begin M[1]:=C[i,j]; M[2]:=i; M[3]:=j; end; }
write(C[i,j]:2,' ');
end;
end;
writeln;
for j:=1 to n do T[j]:=0;
Sum:=0;
for i:=1 to n do begin
writeln;
write(i:2,' man ');
min:=100;
for j:=1 to n do begin
if (C[i,j]<min) and (T[j]=0) then begin min:=C[i,j]; M[i,1]:=i;
M[i,2]:=j; M[i,3]:=C[i,j]; tmj:=j;
end;
write(C[i,j]:2,' ');
end;
T[tmj]:=1;
{M[i,3]:=min;}
Sum:=Sum+M[i,3];
write('=',M[i,3]:2,' man=',M[i,1],' job=',M[i,2]);
end;
writeln;
{for i:=1 to n do begin
for j:=1 to n do begin
if (i<>j) and (M[i,2]=M[j,2]) then begin
M[j,3]:=C[j,1];
for z:=1 to n do begin
if (M[j,3]>C[j,z]) and (z<>M[j,2]) then begin M[j,3]:=C[j,z];
M[j,2]:=z; end;
end;
end;
end;
writeln('=',M[i,3]:2,' man=',M[i,1],' job=',M[i,2]);
end;
}
write('sum=',Sum);
readln;
end.
Программа 11.Назначение на работу.
/*
Назначение на работу.
Рассматривается случай: 6 работ и 6 желающих.
*/
//Назначение на работу. Реализовано на Turbo C++.
#include <stdio.h>
#include <iostream.h>
#include <stdlib.h>
#include <conio.h>
#define k 6
int Sum,tmj,i,j,zj,min,tmp,min2,tmj2,p,q,ki;
int M[k][4], C[k][k], T[k][2], Temper[k][2];
char a;
/*struct myst
{int cel;
float rac;
};
myst ctpyk[k];*/
main()
{
Sum=0;
min=100;
for(i=1;i<k;i++)
{ T[i][1]=0;
printf("\n");
for(j=1;j<k;j++)
{C[i][j]=rand()/1000 +1;
// printf(" %d ", C[i][j]);
}
}
for(i=1;i<k;i++)
{
min=100;
printf("\n");
for(j=1;j<k;j++)
{
if(C[i][j]<min/* T[j][1]==0*/)
{
if(T[j][1]==0)
{
min=C[i][j]; //m[i][1] - 4el, m[i][2] -job, m[i][3]
- stoimost.
M[i][1]=i;
M[i][2]=j;
M[i][3]=C[i][j];
tmj=j;
}
/* else
{
if(C[i][j]<C[T[j][2]][j])
{
ki=T[j][2];
T[j][2]=0;
// T[j][1]=0;
min=C[i][j];
M[i][1]=i;
M[i][2]=j;
M[i][3]=C[i][j];
tmj=j;
for(zj=1;zj<k;zj++)
{
min2=100;
if(C[ki][zj]<min2 zj!=tmj
T[zj][1]==0)
{
min2=C[ki][zj];
tmj2=zj;
M[ki][1]=ki;
M[ki][2]=zj;
M[ki][3]=C[ki][zj];
}
}
T[tmj2][2]=ki;
T[tmj2][1]=min2;
}
*/
}
printf(" %d ", C[i][j]);
}
T[tmj][2]=i;
T[tmj][1]=min;
//na4alo mega funkcii
/* if(C[i][j]<min T[j][1]!=0)
{
for(p=1;pk;p++)
{
if(C[T[tmj][2]][p]
}
}
*/
//konec.
Sum=Sum+M[i][3];
printf(" $= %d, man= %d, job= %d ",M[i][3],M[i][1],M[i][2]);
}
/* for(i=0;i<k;i++)
{ctpyk[i].cel=rand();
ctpyk[i].rac=rand()/1000;
printf("%d %f \n", ctpyk[i].cel, ctpyk[i].rac);}
*/
scanf("%d",a);
return 0;
}
В лекции 11 дана реализация алгоритма "Ханойская башня". Здесь используется другой подход. В программе реализован пользовательский интерфейс с развитым эргономическим компонентом. Пользователю предоставляется возможность самому решить поставленную задачу. В программе использована работа с видеостраницами.
Постановка задачи.
На стержне в исходном порядке находится дисков, уменьшающихся по размеру снизу вверх. Диски должны быть переставлены на стержень в исходном порядке при использовании в случае необходимости промежуточного стержня для временного хранения дисков. В процессе перестановки дисков обязательно должны соблюдаться правила: одновременно может быть переставлен только один самый верхний диск (с одного из стержней на другой); ни в какой момент времени диск не может находиться на другом диске меньшего размера.
Программа 12. Ханойская башня.
{Программа реализована с помощью абстрактного типа данных –
стек для произвольного числа дисков. Число колец задается
константой maxc. Программа написана на языке
программирования Turbo-Pascal}
program Tower;
uses Crt, Graph;
const maxc = 4;{Максимальное число колец на одной башне}
type TTower = record
num: byte;
sizes: array[1..maxc] of byte;
up: byte;
end;
var Towers: array[1..3] of TTower;
VisVP, ActVP: byte; {видимая и активная видеостраницы}
ActTower: byte;
Message: String;
Win: boolean;
font1: integer;
function CheckEnd: boolean;
var res: boolean;
i: byte;
begin
res:=False;
if (Towers[2].num=maxc) or (Towers[3].num=maxc) then res:=true;
CheckEnd:=res;
end;
procedure BeginDraw;
begin
SetActivePage(ActVP);
end;
procedure EndDraw;
begin
VisVP:=ActVP;
SetVisualPage(VisVP);
if VisVP=1 then ActVP:=0 else ActVP:=1;
end;
procedure Init;
var grDr, grM: integer;
ErrCode: integer;
i: integer;
begin
grDr:=VGA;
grM:=VGAMed;
InitGraph(grDr, grM, 'c:\borland\tp\bgi');
ErrCode:=GraphResult;
if ErrCode <> grOk then
begin
Writeln('Graphics error:', GraphErrorMsg(ErrCode));
Halt;
end;
Towers[1].num:=maxc;
Towers[1].up:=0;
for i:=0 to maxc-1 do
Towers[1].sizes[i+1]:=maxc-i;
Towers[2].num:=0;
Towers[2].up:=0;
for i:=0 to maxc-1 do
Towers[2].sizes[i+1]:=0;
p>Towers[3].num:=0;
Towers[3].up:=0;
for i:=0 to maxc-1 do
Towers[2].sizes[i+1]:=0;
ActTower:=1;
VisVP:=0; ActVP:=1;
SetVisualPage(VisVP);
SetActivePage(ActVP);
Message:='';
Win:=False;
end;
procedure Close;
begin
closegraph;
end;
procedure DrawTower(x, y: integer; n: integer);
var i: integer;
begin
if n=ActTower then
SetColor(yellow);
Line(x, y, x, y+15+maxc*15);
for i:=1 to Towers[n].num do
begin
Rectangle(x-10*Towers[n].sizes[i], y+15+15*(maxc-i+1),
x+10*Towers[n].sizes[i], y+15+15*(maxc-i))
end;
if Towers[n].up<>0 then
begin
Rectangle(x-10*Towers[n].up, y-15, x+10*Towers[n].up, y-30);
end;
SetColor(White);
end;
procedure DrawInfo;
begin
OutTextXY(50, 20, 'Ханойская башня.);
OutTextXY(80, 40, 'Работа с программой: стрелки влево-вправо - выбор
башни');
OutTextXY(130, 60, 'текущая башня выделяется желтым цветом');
OutTextXY(60, 80, 'стрелка вверх - поднять кольцо, стрелка вниз -
положить кольцо');
OutTextXY(80, 100, '(две последние операции выполняются для активной
башни)');
end;
procedure Draw;
begin
BeginDraw;
ClearDevice;
OutTextXY(180, 140, Message); Message:='';
DrawTower(150, 200, 1);
DrawTower(300, 200, 2);
DrawTower(450, 200, 3);
if win then
begin
SetTextStyle(GothicFont, HorizDir, 8);
SetColor(Red);
Outtextxy(70, 0, 'Congratulations');
Outtextxy(160, 70, 'You win');
SetTextStyle(DefaultFont, HorizDir, 1);
SetColor(White);
OutTextXY(250, 330, 'Press any key');
end
else
DrawInfo;
EndDraw;
end;
procedure MainCycle;
var ch: char;
ex: boolean;
up: byte;
begin
ex:=False;
repeat
if KeyPressed then
begin
ch:=ReadKey;
case ch of
#27: begin
Ex:=True;
end;
#77: begin
up:=Towers[ActTower].up;
Towers[ActTower].up:=0;
inc(ActTower);
if ActTower>3 then ActTower:=1;
Towers[ActTower].up:=up;
end;
#75: begin
up:=Towers[ActTower].up;
Towers[ActTower].up:=0;
dec(ActTower);
if ActTower<1 then ActTower:=3;
Towers[ActTower].up:=up;
end;
#80: begin {вниз}
if Towers[ActTower].up<>0 then
begin
if Towers[ActTower].num=0 then
begin
Towers[ActTower].num:=Towers[ActTower].num+1;
Towers[ActTower].sizes[Towers[ActTower].num]:=Towers[ActTower].up;
Towers[ActTower].up:=0;
end
else
begin
if
Towers[ActTower].sizes[Towers[ActTower].num]>Towers[ActTower].up then
begin
Towers[ActTower].num:=Towers[ActTower].num+1;
Towers[ActTower].sizes[Towers[ActTower].num]:=Towers[ActTower].up;
Towers[ActTower].up:=0;
end
else
Message:='Это кольцо сюда опускать нельзя';
end;
end;
end;
#72: begin {вверх}
if Towers[ActTower].num<>0 then
begin
Towers[ActTower].num:=Towers[ActTower].num-1;
Towers[ActTower].up:=Towers[ActTower].sizes[Towers[ActTower].num+1];
Towers[ActTower].sizes[Towers[ActTower].num+1]:=0;
end;
end;
end;
if CheckEnd then
begin
Win:=True;
ex:=True;
end;
Draw;
end;
until ex;
end;
begin
Init;
Draw;
MainCycle;
if win then repeat until keypressed;
Close;
end.
Тезей должен был найти выход из Критского лабиринта или погибнуть, убитый Минотавром. Но что поразительно: найти вход в лабиринт - задача не менее трудная.
Здесь не представляется возможным описать все мыслимые лабиринты, да это и не требуется. Мы займемся простыми лабиринтами, построенными на прямоугольнике $$m\times n$$, где $$m,n$$ — положительные целые числа. Внутри и на границах прямоугольника поставлены стенки по ребрам покрывающей его единичной квадратной сетки. Чтобы построить из прямоугольника лабиринт, выбьем одну единичную стенку на одной из сторон прямоугольника (получится вход в лабиринт); выбьем одну единичную стенку на противоположной стороне (получится выход) и еще удалим какое-то число строго внутренних стенок. Говорят, что лабиринт имеет решение, если между входом и выходом внутри лабиринта есть путь в виде ломаной, не имеющей общих точек со стенками. Решение единственно, если любые два таких пути проходят через одни и те же внутренние ячейки сетки. На рис. 17.1 приведен пример лабиринта $$5\times 5$$.
(рис 17.1) Пример лабиринтаОдин из возможных подходов к решению таков. Выбираем вход; затем, начав от него, добавляем по одной ячейке к главному пути-решению, пока он не достигнет выходной стороны. После этого удаляем некоторые внутренние стенки так, чтобы все клетки оказались соединенными с главным путем. Чтобы главный путь не получился прямым коридором, следует при его построении предусмотреть случайные повороты. Программа должна также следить за тем, чтобы при построении главного пути или при открытии боковых ячеек не нарушалась единственность решения. Наблюдательный читатель заметит, что определение единственности решения не годится в случае, когда путь заходит в боковой тупик и затем возвращается.
Программу можно написать почти на любом из процедурных языков.
Программа 1. Лабиринт.
{Программно задаются вход и выход. Нажимая на клавишу "Enter",
перебираем всевозможные пути от входа до выхода в лабиринте.
Выход из программы по клавише "Esc".
Алгоритм реализован на языке программирования Turbo-Pascal}
program Maze;
uses
Graph, Crt;
var
m,n: Integer;
Matrix: array [1..100,1..100] of Boolean;
Start,Finish: Integer;
procedure PrepareGraph;
var
Driver,Mode: Integer;
begin
Driver:=VGA;
Mode:=VGAHi;
InitGraph(Driver,Mode,'c:\borland\tp\bgi');
end;
procedure DisplayMaze(x1,y1,x2,y2: Integer);
var
i,j: Integer;
dx,dy: Real;
begin
SetFillStyle(1,8);
SetColor(15);
dx:=(x2-x1)/m;
dy:=(y2-y1)/n;
for i:=1 to n do
for j:=1 to m do
if not Matrix[i,j] then
Rectangle(Round(x1+(i-1)*dx),Round(y1+(j-1)*dy),
Round(x1+i*dx),Round(y1+j*dy));
end;
function CreatesPath(i,j: Integer): Boolean;
var
Result: Boolean;
Count: Integer;
ii,jj: Integer;
begin
Count:=0;
if (i>1) and Matrix[i-1,j] then Inc(Count);
if (i<m) and Matrix[i+1,j] then Inc(Count);
if (j>1) and Matrix[i,j-1] then Inc(Count);
if (j<m) and Matrix[i,j+1] then Inc(Count);
if Count>1 then Result:=true else Result:=false;
CreatesPath:=Result;
end;
function DeadEnd(i,j: Integer): Boolean;
var
Result: Boolean;
Count: Integer;
begin
Count:=0;
if (i=2) or CreatesPath(i-1,j) then Inc(Count);
if (i=m-1) or CreatesPath(i+1,j) then Inc(Count);
if (j=2) or CreatesPath(i,j-1) then Inc(Count);
if (j=n-1) or CreatesPath(i,j+1) then Inc(Count);
if Count=4 then Result:=true else Result:=false;
DeadEnd:=Result;
end;
function CreateMaze: Boolean;
var
i,j: Integer;
di,dj: Integer;
Result: Boolean;
begin
Randomize;
for i:=1 to n do
for j:=1 to m do Matrix[i,j]:=false;
Start:=Random(m-2)+2;
i:=Start;
j:=2;
Matrix[Start,1]:=true;
repeat
Matrix[i,j]:=true;
di:=0;
dj:=0;
while (di=0) and (dj=0) do begin
di:=1-Random(3);
if (i+di=1) or (i+di=m) then di:=0;
if di=0 then dj:=1-Random(3);
if j+dj=1 then dj:=0;
if CreatesPath(i+di,j+dj) then begin
di:=0;
dj:=0;
end;
end;
i:=i+di;
j:=j+dj;
until DeadEnd(i,j) or (j=n);
Finish:=i;
Matrix[Finish,n]:=true;
if j<n then Result:=false else Result:=true;
CreateMaze:=Result;
end;
begin
m:=6;
n:=6;
PrepareGraph;
repeat
ClearDevice;
repeat until CreateMaze;
DisplayMaze(120,40,520,440);
repeat until KeyPressed;
until ReadKey=#27;
CloseGraph;
end.
Программа 2. Лабиринт.
{Лабиринт реализуется автоматически, без участия пользователя.
Алгоритм реализован на языке программирования Turbo-Pascal }
uses graph,crt;
var
mpos,npos,m,n,delx,x,y,t,gd,gm,i,k:integer;
begin
randomize;
writeln('Input labyrint size (x and y)');
readln(m,n);
writeln('Input entranceexit coordinates (mpos<m and npos<m)');
readln(mpos,npos);
initgraph(gd,gm,'c:\borland\tp\bgi');
for i:=1 to m do
begin
for k:=1 to n do
begin
rectangle(90+10*i,90+10*k,90+10*i+10,90+10*k+10);
end;
end;
setfillstyle(1,0);
setcolor(0);
line(100+(mpos-1)*10+1,100,100+(mpos-1)*10+9,100);
line(100+(npos-1)*10+1,100+n*10,100+(npos-1)*10+9,100+n*10);
y:=n;
x:=npos;
readln;
while y>1 do
begin
delx:=random(m)-x+1;
if y=2 then delx:=mpos-x;
i:=91+x*10;
if i<90+(x+delx)*10 then
begin
while i<>90+(x+delx)*10 do
begin
i:=i+1;
line(i,91+y*10,i,99+y*10);
end;
end;
if i>91+(x+delx)*10 then
begin
while i<>91+(x+delx)*10 do
begin
i:=i-1;
line(i,91+y*10,i,99+y*10);
end;
end;
x:=x+delx;
line(91+10*x,90+y*10,99+10*x,90+y*10);
y:=y-1;
end;
readln;
end.
Строится бинарное дерево. В узлы дерева засылаются целые положительные числа, выбранные случайным образом. После задания значений вершин на каждом уровне эти значения выводятся на экран, начиная с корневой. Пользователю предлагается сделать выбор номера уровня, в нем определяется максимальное значение и выводится на экран.
Программа 3. Поиск максимального элемента.
{ Алгоритм реализован на языке программирования Turbo-Pascal}
uses crt;
type sp=^tree;
tree=record
val:integer;
l:sp;
r:sp;
end;
var
t:sp;
nh, max,h,i:integer;
procedure find(t:sp; h,nh:integer);
begin
if t=nil then exit;
if h=nh then
begin
if t^.val> max then max:=t^.val;
end
else
begin
find(t^.l,h+1,nh);
find(t^.r,h+1,nh);
end;
end;
procedure zadtree(var t:sp; h,nh:integer);
begin
if h=5 then
begin
new(t);
t^.l:=nil;
t^.r:=nil;
t^.val:=random(100);
end
else
begin
new(t);
zadtree(t^.l, h+1,nh);
zadtree(t^.r, h+1,nh);
t^.val:=random(100);
end;
end;
procedure writetree(t:sp; h,nh:integer);
begin
if t=nil then exit;
if h=nh then
begin
write(t^.val,' ');
end
else
begin
writetree(t^.l,h+1,nh);
writetree(t^.r,h+1,nh);
end;
end;
begin
clrscr;
randomize;
t:=nil;
zadtree(t,1,nh);
for i:=1 to 5 do
begin
writetree(t,1,i);
writeln;
end;
max:=0;
write('vvedite uroven ');
readln(nh);
find(t,1,nh);
write('max= ',max);
readln;
end.
Условие задачи. Найти все такие расстановки восьми ферзей на шахматной доске, при которых ферзи не бьют друг друга.
Анализ задачи. Пусть $$A$$ - множество искомых расстановок (конфигураций). Рассмотрим следующий подход к решению задачи. Будем искать множество конфигураций $$B$$ со следующими свойствами:
С помощью процедуры из пункта 3 будем генерировать по очереди все элементы из $$B$$ ; для элементов из $$B$$ проверяем (см. пункт 2) принадлежит ли он $$A$$: в результате в силу 1 свойства будут порождены все элементы $$A$$.
Заметим теперь, что ферзи, которые не бьют друг друга, должны располагаться на разных горизонталях. Поэтому можно упорядочить ферзи и всегда ставить $$k$$ -го ферзя на $$k$$ -ю горизонталь. Тогда в качестве $$B$$ можно взять множество конфигураций, в которых на каждой из первых $$N$$ горизонталей стоит ровно по одному ферзю, причем никакие два ферзя не бьют друг друга.
Программа 4. Расстановка восьми ферзей на шахматной доске.
{ Программа выдает все комбинации ферзей, которые не бьют друг друга.
Алгоритм реализован на языке программирования Turbo-Pascal }
program ferz;
uses crt;
const desksize=8;
type sizeint=1..desksize;
unuses=set of sizeint;
combinates=array[shortint] of sizeint;
var num:byte;
combinate:combinates;
unuse:unuses;
function attack(combinate:combinates):boolean;
var i,j:byte;
rightdiag,leftdiag:combinates;
begin
attack:=false;
for i:=1 to desksize do
begin
leftdiag[i]:=i+combinate[i];
rightdiag[i]:=i-combinate[i];
end;
for j:=1 to desksize do
for i:=1 to desksize do
begin
if (i<>j) and ((leftdiag[i]=leftdiag[j])or(rightdiag[i]=rightdiag[j]))
then
begin
attack:=true;
exit;
end;
end;
end;
procedure output(combinate:combinates);
var i,j:byte;
begin
for i:=1 to desksize do
for j:=1 to desksize do
begin
gotoxy(i,j);
if(combinate[i]=j) then write(#2) else write(' ');
end;
readln;
end;
procedure create(num:byte; unuse:unuses; combinate:combinates);
var i:byte;
begin
if num<=desksize then
for i:=1 to desksize do
begin
if i in unuse then
begin
combinate[num]:=i;
create(num+1,unuse-[i],combinate);
end;
end
else if not attack(combinate) then output(combinate);
end;
begin
textmode(c40);
clrscr;
unuse:=[1..desksize];
create(1,unuse,combinate);
end.
В лекциях 14 и 15 мы рассматривали более подробно различные способы сортировки. Здесь мы напоминаем некоторые из них и приводим пример программ.
Сортировка по возрастанию - это сортировка, при которой записи упорядочиваются по возрастанию значений ключевых полей.
Сортировка по убыванию - это сортировка, при которой записи упорядочиваются по убыванию значений ключевых полей.
Сортировка методом пузырька (
Сортировка по ключу - это сортировка записей с упорядочением по значению указанного поля или группы полей.
Сортировка слиянием - это
Сортировка Батчера - это сортировка, внутренний алгоритм которой работает за время $$O(N\cdot\log (N))$$.
Программа 5. Сортировка массива по возрастанию методом пузырька.
//Данные, которые нужно отсортировать, берутся из файла "massiv.txt",
//результат записывается в массив int mas['K'] и выводится на экран
// Алгоритм реализован на Turbo C++.
#include <conio.h>
#include <stdio.h>
#define K 1000; //Размер массива
int mas['K'];
int n;
void puzirek()//функция сортирует массив по возрастанию методом пузырька
{
int i,j,t;
for(i=0;i<n;i++)
for(j=1;j<n-i;j++)
if(mas[j]<mas[j-1])
{
t=mas[j];
mas[j]=mas[j-1];
mas[j-1]=t;
}
}
int main()
{
clrscr();
FILE *filePointer=fopen("massiv.txt","r");
int i=0;
while (!feof(filePointer))
{
fscanf(filePointer,"%d",mas[i]);
i++;
}
n=i;
puzirek();
for(i=0;i<n;i++)
printf("%d ",mas[i]);
//scanf("%d",n);
getch();
return 0;
}
Программа 6. Пузырьковая сортировка и сортировка методом прямого выбора.
{Сортировка. Алгоритм реализован на языке программирования Turbo-Pascal}
uses crt;
var
M, N : array[0..10] of integer;
i:integer;
procedure Input;
begin
for i := 0 to 10 do
begin
writeln('Число');
readln(M[i]); {Ввод массива}
end;
end;
Procedure Sort1; {Пузырьковый метод сортировки}
var
q,i,x:integer;
begin
for i:=10 downto 0 do
begin
for q:=0 to 10 do
if M[q]<M[q+1] then
begin
x:=M[q];
M[q]:=M[q+1];
M[q+1]:=x
end;
end;
end;
procedure Sort2; {Метод прямого выбора}
var
i,j,k,x:integer;
begin
for i:=0 to 9 do
begin
k:=i;
x:=M[i];
for j:=i+1 to 10 do
if M[j] >x then begin k:=j; x:=M[k];
end;
M[k]:= M[i];
M[i]:=x;
end;
end;
{---------------------------------------------}
begin
clrscr;
input; {Ввод исходного массива}
writeln('Исходный массив');
for i:=0 to 10 do write(M[i],' '); {Вывод исходного массива}
writeln;
Sort1;{Сортировка массива методом пузырька}
writeln ('Сортированный массив');
for i:=0 to 10 do write(M[i],' '); {Вывод отсортированного массива}
input; {Ввод исходного массива}
writeln('Исходный массив');
for i:=0 to 10 do write(M[i],' '); {Вывод исходного массива}
writeln;
sort2;
writeln ('Сортированный массив методом прямого выбора');
for i:=0 to 10 do write(M[i],' '); {Вывод отсортированного массива}
readln;
end.
Программа 7. Сестры.
//Две строки матрицы назовем сестрами, если совпадают
//множества чисел, встречающихся в этих строках. Программа
//определяет всех сестер матрицы, если они есть,
//и выводит номера строк. Алгоритм реализован на Turbo C++.
//#include <graphics.h>
#include <stdlib.h>
//#include <string.h>
#include <stdio.h>
#include <conio.h>
//#include <math.h>
#include <dos.h>
#include <values.h>
#include <iostream.h>
const n=4,//кол-во строк
m=4; //столбцов
int m1[n][m];
//исходный массив
struct mas{int i,i1;};
//i-индекс сравниваемой строки с i1 строкой
mas a[n*2];
//массив типа mas, где будут лежать сестры, пример) a[1].i и a[1].i1 -
сестры
void main()
{clrscr();
int i,j;
randomize();
for( i=0;i<n;i++)
for( j=0;j<m;j++)
m1[i][j]=random(2);
//случайным образом в массив заносим цифры
for(i=0;i<n;i++)
{printf("\n %d) ",i);
for(int j=0;j<m;j++)
printf(" %d",m1[i][j]);
//распечатываем этот массив
}
int min,
p;
//индекс минимального элемента после s-го элемента i-ой строки
//сортировка строк массива по возрастанию
for(i=0;i<n;i++)//i-сортировка i-ой строки
{
for(int s=0;s<m-1;s++)
{min=m1[i][s+1];
for(int j=s;j<m;j++)
if(m1[i][j]<=min){min=m1[i][j];p=j;}
//запоминаем минимальный элемент в ряде после s-го элемента
if(m1[i][s]>=min)
{m1[i][p]=m1[i][s];m1[i][s]=min;}
//меняем местами s-й и p-й элемент,если s-й>p-го(минимального)
}
}
printf("\n");
for(i=0;i<n;i++)
{printf("\n %d) ",i);
for(int j=0;j<m;j++)
printf(" %d",m1[i][j]);
//выводим отсортированный массив
}
int s=0 //сколько элементов в i-й строке совпадают с
эл-ми i1 строки, k=0;
//сколько строк совпали
int i1;
for(i=0;i<n-1;i++) //верхняя строка i
for( i1=i+1;i1<n;i1++) //нижняя строка i1
{s=0;
for(int j=0;j<m;j++)
//сравнение идет по j-му столбцу
// ! !
if(m1[i][j]==m1[i1][j])s++; //если соответствующие элементы в
//i-й и i1-й строки совпадают, то кол-во совпавших увеличивается на 1
if(s==m){a[k].i=i;a[k].i1=i1;k++;}
//если все элементы i-й и i1-й строки совпали, то они сестры
}
printf("\nСестры :");
for(i=0;i<k;i++)
printf("\n %d и %d",a[i].i,a[i].i1);
//распечатываем a[i].i-ю и a[i].i1-ю сестру
getch();
}
Программа 8. Поиск узоров из простых чисел.
//Построить матрицу А(15 Х 15)таким образом: А(8,8)=1, затем
//по спирали против часовой стрелки,
//увеличивая значение очередного элемента на единицу
//и выделяя все простые числа красным цветом, заполнить матрицу
//Алгоритм реализован на Turbo C++.
#include <stdio.h>
#include <conio.h>
void main(void)
{
clrscr();
int mas[15][15];
int n=1,x=6,y=6,k=1;
int i,j;
while(1){
mas[x][y]=k++;
switch(n){
case 1: x++;break;
case 2: y--;break;
case 3: x--;break;
case 4: y++;break;
}
if(x==15) break;
if(x==y x<6) n=4;
else if(x+y==12 x<6) n=1;
else if(x+y==12 x>6) n=3;
else if(x==y+1 x>6) n=2;
}
for(i=0;i<15;i++)
{
for(j=0;j<15;j++)
{
textcolor(12);
if(mas[j][i]>2)
for(k=2;k<mas[j][i];k++)
if(mas[j][i]%k==0) textcolor(15);
cprintf("%3d ",mas[j][i]);
}
printf("\n");
}
getch();
}
Программа 9. Сортировка строк матрицы.
//Cортировка строк матрицы. В каждой строке подсчитывается сумма
//простых чисел. Полученный вектор упорядочивается по возрастанию.
//Строки матрицы переставляются по новому вектору.
//Алгоритм реализован на Turbo C++.
#include<stdio.h>
#include<conio.h>
#define n 5
struct summa
{
int value;
int idx;
} sum,massum[n],a;
void main(void){
clrscr();
int mas1[n][n],mas[n][n]={{1,1,1,1,1},
{3,16,11,6,4},
{8,10,15,23,1},
{3,8,10,15,3},
{7,3,20,15,10}};
int i,j,k,flag;
for(i=0;i<n;i++){
sum.value=0;
for(j=0;j<n;j++){
flag=0;
if(mas[i][j]>2)
for(k=2;k<mas[i][j];k++)
if(mas[i][j]%k==0) flag=1;
if(flag==0) sum.value=sum.value+mas[i][j];
}
sum.idx=i;
massum[i]=sum;
}
for(i=0;i<n-1;i++)
for(j=0;j<n-1-i;j++){
if (massum[j].value>massum[j+1].value){
a=massum[j];
massum[j]=massum[j+1];
massum[j+1]=a;
}
}
for(i=0;i<n;i++)
for(j=0;j<n;j++)
mas1[i][j]=mas[massum[i].idx][j];
for(i=0;i<n;i++){
for(j=0;j<n;j++)
printf("%3d ",mas[i][j]);
printf("\n");
}
printf("\n\n\n");
for(i=0;i<n;i++){
for(j=0;j<n;j++)
printf("%3d ",mas1[i][j]);
printf("\n");
}
getch();
}
Эта задача состоит в следующем. Пусть имеется $$n$$ работ и $$n$$ кандидатов для выполнения этих работ. Назначение кандидата $$i$$ на работу $$j$$ связано с затратами $$c_{ij}$$ $$(i,j=1,2,\ldots,n)$$. Требуется найти назначение кандидатов на все работы, дающее минимальные суммарные затраты; при этом каждого кандидата можно назначить только на одну работу и каждая работа может быть занята только одним кандидатом.
Иначе говоря, решение этой задачи представляет собой перестановку ( $$p_1,p_2,\ldots,p_n$$ ) чисел $$(1, 2, \ldots, n)$$ ; каждое из производимых назначений описывается соответствием $$i\to p_i$$ ( $$i=1,\ldots,n$$ ). Указанные условия единственности при этом автоматически выполняются, и нашей целью является минимизация суммы$$\sum_{i=1}^n c_{ip_i}$$ по всем перестановкам ( $$p_1,p_2,\ldots,p_n$$ ).
Перед нами типичная экстремальная комбинаторная задача. Ее решение путем прямого перебора, то есть вычисления значений функции 17.1 на всех перестановках и сравнения, практически невозможно при сколько-нибудь больших $$n$$, поскольку число перестановок равно $$n!=1\cdot 2\cdot 3\cdots (n-1)n$$. Попытаемся свести дело к линейному программированию.
Конечное множество, на котором задана целевая функция 17.1, представляет собой множество всех перестановок чисел $$(1, 2, \ldots, n)$$. Как известно, каждая такая перестановка может быть описана точкой в $$n^2$$ -мерном евклидовом пространстве; эту точку удобнее всего представить в виде $$n\times n$$ -матрицы $$X=\|x_{ij}\|$$. Элементы $$x_{ij}$$ интерпретировать следующим образом:
$$x_{ij}=1$$, если i-й кандидат назначается на j-ю работу,
$$x_{ij}=0$$, в противном случае.
Элементы матрицы должны быть подчинены двум условиям:$$\sum_{j=1}^{n}x_{ij}=1,\quad i=1,2,\ldots, n,$$ $$\sum_{i=1}^{n}x_{ij}=1,\quad j=1,2,\ldots, n.$$ Условия 17.3 и 17.4 говорят о том, что в каждой строке и в каждом столбце матрицы $$X$$ имеется ровно по одной единице. Говоря неформально, условие 17.3 означает, что каждый кандидат может быть назначен только на одну работу, а условие 17.4 — что каждая работа предназначена только для одного кандидата. (Матрицу перестановок можно получить из единичной матрицы путем некоторой перестановки ее строк.)
Теперь задача заключается в нахождении чисел $$x_{ij}$$, удовлетворяющих условиям 17.2, 17.3, 17.4 и минимизирующих суммарные затраты 17.1, которые теперь можно переписать в виде$$\sum_{i=1}^{n}\sum_{j=1}^nc_{ij}x_{ij}.$$ Казалось бы, что к полученной задаче методы линейного программирования непосредственно применить нельзя, ибо в силу условий 17.2 она формально является целочисленной. Заменим условие 17.2 на условие неотрицательности переменных$$x_{ij}>0.$$ Тем самым мы получаем обычную задачу линейного программирования. В нашем случае требование целочисленности 17.2 будет выполняться автоматически.
Программа 10.Назначение на работу.
program one;{Назначение на работу.
Рассматривается случай: 10 работ и 10 желающих.
реализовано на Turbo-Pascal}
uses crt;
const n=10;
var C : array [1..n,1..n] of integer;
T : array [1..n] of integer;
M : array [1..n,1..4] of integer;
Sum,tmj,z,min,i,j,tmp:integer;
begin
clrscr;
randomize;
write('work - ');
for i:=1 to n do write(i:2,' ');
for i:=1 to n do begin
writeln;
write(i:2,' man ');
for j:=1 to n do begin
C[i,j]:=random(100);
{if M[i,j]>max then max:=M[i,j];}
{if C[i,j]<min then begin M[1]:=C[i,j]; M[2]:=i; M[3]:=j; end; }
write(C[i,j]:2,' ');
end;
end;
writeln;
for j:=1 to n do T[j]:=0;
Sum:=0;
for i:=1 to n do begin
writeln;
write(i:2,' man ');
min:=100;
for j:=1 to n do begin
if (C[i,j]<min) and (T[j]=0) then begin min:=C[i,j]; M[i,1]:=i;
M[i,2]:=j; M[i,3]:=C[i,j]; tmj:=j;
end;
write(C[i,j]:2,' ');
end;
T[tmj]:=1;
{M[i,3]:=min;}
Sum:=Sum+M[i,3];
write('=',M[i,3]:2,' man=',M[i,1],' job=',M[i,2]);
end;
writeln;
{for i:=1 to n do begin
for j:=1 to n do begin
if (i<>j) and (M[i,2]=M[j,2]) then begin
M[j,3]:=C[j,1];
for z:=1 to n do begin
if (M[j,3]>C[j,z]) and (z<>M[j,2]) then begin M[j,3]:=C[j,z];
M[j,2]:=z; end;
end;
end;
end;
writeln('=',M[i,3]:2,' man=',M[i,1],' job=',M[i,2]);
end;
}
write('sum=',Sum);
readln;
end.
Программа 11.Назначение на работу.
/*
Назначение на работу.
Рассматривается случай: 6 работ и 6 желающих.
*/
//Назначение на работу. Реализовано на Turbo C++.
#include <stdio.h>
#include <iostream.h>
#include <stdlib.h>
#include <conio.h>
#define k 6
int Sum,tmj,i,j,zj,min,tmp,min2,tmj2,p,q,ki;
int M[k][4], C[k][k], T[k][2], Temper[k][2];
char a;
/*struct myst
{int cel;
float rac;
};
myst ctpyk[k];*/
main()
{
Sum=0;
min=100;
for(i=1;i<k;i++)
{ T[i][1]=0;
printf("\n");
for(j=1;j<k;j++)
{C[i][j]=rand()/1000 +1;
// printf(" %d ", C[i][j]);
}
}
for(i=1;i<k;i++)
{
min=100;
printf("\n");
for(j=1;j<k;j++)
{
if(C[i][j]<min/* T[j][1]==0*/)
{
if(T[j][1]==0)
{
min=C[i][j]; //m[i][1] - 4el, m[i][2] -job, m[i][3]
- stoimost.
M[i][1]=i;
M[i][2]=j;
M[i][3]=C[i][j];
tmj=j;
}
/* else
{
if(C[i][j]<C[T[j][2]][j])
{
ki=T[j][2];
T[j][2]=0;
// T[j][1]=0;
min=C[i][j];
M[i][1]=i;
M[i][2]=j;
M[i][3]=C[i][j];
tmj=j;
for(zj=1;zj<k;zj++)
{
min2=100;
if(C[ki][zj]<min2 zj!=tmj
T[zj][1]==0)
{
min2=C[ki][zj];
tmj2=zj;
M[ki][1]=ki;
M[ki][2]=zj;
M[ki][3]=C[ki][zj];
}
}
T[tmj2][2]=ki;
T[tmj2][1]=min2;
}
*/
}
printf(" %d ", C[i][j]);
}
T[tmj][2]=i;
T[tmj][1]=min;
//na4alo mega funkcii
/* if(C[i][j]<min T[j][1]!=0)
{
for(p=1;pk;p++)
{
if(C[T[tmj][2]][p]
}
}
*/
//konec.
Sum=Sum+M[i][3];
printf(" $= %d, man= %d, job= %d ",M[i][3],M[i][1],M[i][2]);
}
/* for(i=0;i<k;i++)
{ctpyk[i].cel=rand();
ctpyk[i].rac=rand()/1000;
printf("%d %f \n", ctpyk[i].cel, ctpyk[i].rac);}
*/
scanf("%d",a);
return 0;
}
В лекции 11 дана реализация алгоритма "Ханойская башня". Здесь используется другой подход. В программе реализован пользовательский интерфейс с развитым эргономическим компонентом. Пользователю предоставляется возможность самому решить поставленную задачу. В программе использована работа с видеостраницами.
Постановка задачи.
На стержне в исходном порядке находится дисков, уменьшающихся по размеру снизу вверх. Диски должны быть переставлены на стержень в исходном порядке при использовании в случае необходимости промежуточного стержня для временного хранения дисков. В процессе перестановки дисков обязательно должны соблюдаться правила: одновременно может быть переставлен только один самый верхний диск (с одного из стержней на другой); ни в какой момент времени диск не может находиться на другом диске меньшего размера.
Программа 12. Ханойская башня.
{Программа реализована с помощью абстрактного типа данных –
стек для произвольного числа дисков. Число колец задается
константой maxc. Программа написана на языке
программирования Turbo-Pascal}
program Tower;
uses Crt, Graph;
const maxc = 4;{Максимальное число колец на одной башне}
type TTower = record
num: byte;
sizes: array[1..maxc] of byte;
up: byte;
end;
var Towers: array[1..3] of TTower;
VisVP, ActVP: byte; {видимая и активная видеостраницы}
ActTower: byte;
Message: String;
Win: boolean;
font1: integer;
function CheckEnd: boolean;
var res: boolean;
i: byte;
begin
res:=False;
if (Towers[2].num=maxc) or (Towers[3].num=maxc) then res:=true;
CheckEnd:=res;
end;
procedure BeginDraw;
begin
SetActivePage(ActVP);
end;
procedure EndDraw;
begin
VisVP:=ActVP;
SetVisualPage(VisVP);
if VisVP=1 then ActVP:=0 else ActVP:=1;
end;
procedure Init;
var grDr, grM: integer;
ErrCode: integer;
i: integer;
begin
grDr:=VGA;
grM:=VGAMed;
InitGraph(grDr, grM, 'c:\borland\tp\bgi');
ErrCode:=GraphResult;
if ErrCode <> grOk then
begin
Writeln('Graphics error:', GraphErrorMsg(ErrCode));
Halt;
end;
Towers[1].num:=maxc;
Towers[1].up:=0;
for i:=0 to maxc-1 do
Towers[1].sizes[i+1]:=maxc-i;
Towers[2].num:=0;
Towers[2].up:=0;
for i:=0 to maxc-1 do
Towers[2].sizes[i+1]:=0;
p>Towers[3].num:=0;
Towers[3].up:=0;
for i:=0 to maxc-1 do
Towers[2].sizes[i+1]:=0;
ActTower:=1;
VisVP:=0; ActVP:=1;
SetVisualPage(VisVP);
SetActivePage(ActVP);
Message:='';
Win:=False;
end;
procedure Close;
begin
closegraph;
end;
procedure DrawTower(x, y: integer; n: integer);
var i: integer;
begin
if n=ActTower then
SetColor(yellow);
Line(x, y, x, y+15+maxc*15);
for i:=1 to Towers[n].num do
begin
Rectangle(x-10*Towers[n].sizes[i], y+15+15*(maxc-i+1),
x+10*Towers[n].sizes[i], y+15+15*(maxc-i))
end;
if Towers[n].up<>0 then
begin
Rectangle(x-10*Towers[n].up, y-15, x+10*Towers[n].up, y-30);
end;
SetColor(White);
end;
procedure DrawInfo;
begin
OutTextXY(50, 20, 'Ханойская башня.);
OutTextXY(80, 40, 'Работа с программой: стрелки влево-вправо - выбор
башни');
OutTextXY(130, 60, 'текущая башня выделяется желтым цветом');
OutTextXY(60, 80, 'стрелка вверх - поднять кольцо, стрелка вниз -
положить кольцо');
OutTextXY(80, 100, '(две последние операции выполняются для активной
башни)');
end;
procedure Draw;
begin
BeginDraw;
ClearDevice;
OutTextXY(180, 140, Message); Message:='';
DrawTower(150, 200, 1);
DrawTower(300, 200, 2);
DrawTower(450, 200, 3);
if win then
begin
SetTextStyle(GothicFont, HorizDir, 8);
SetColor(Red);
Outtextxy(70, 0, 'Congratulations');
Outtextxy(160, 70, 'You win');
SetTextStyle(DefaultFont, HorizDir, 1);
SetColor(White);
OutTextXY(250, 330, 'Press any key');
end
else
DrawInfo;
EndDraw;
end;
procedure MainCycle;
var ch: char;
ex: boolean;
up: byte;
begin
ex:=False;
repeat
if KeyPressed then
begin
ch:=ReadKey;
case ch of
#27: begin
Ex:=True;
end;
#77: begin
up:=Towers[ActTower].up;
Towers[ActTower].up:=0;
inc(ActTower);
if ActTower>3 then ActTower:=1;
Towers[ActTower].up:=up;
end;
#75: begin
up:=Towers[ActTower].up;
Towers[ActTower].up:=0;
dec(ActTower);
if ActTower<1 then ActTower:=3;
Towers[ActTower].up:=up;
end;
#80: begin {вниз}
if Towers[ActTower].up<>0 then
begin
if Towers[ActTower].num=0 then
begin
Towers[ActTower].num:=Towers[ActTower].num+1;
Towers[ActTower].sizes[Towers[ActTower].num]:=Towers[ActTower].up;
Towers[ActTower].up:=0;
end
else
begin
if
Towers[ActTower].sizes[Towers[ActTower].num]>Towers[ActTower].up then
begin
Towers[ActTower].num:=Towers[ActTower].num+1;
Towers[ActTower].sizes[Towers[ActTower].num]:=Towers[ActTower].up;
Towers[ActTower].up:=0;
end
else
Message:='Это кольцо сюда опускать нельзя';
end;
end;
end;
#72: begin {вверх}
if Towers[ActTower].num<>0 then
begin
Towers[ActTower].num:=Towers[ActTower].num-1;
Towers[ActTower].up:=Towers[ActTower].sizes[Towers[ActTower].num+1];
Towers[ActTower].sizes[Towers[ActTower].num+1]:=0;
end;
end;
end;
if CheckEnd then
begin
Win:=True;
ex:=True;
end;
Draw;
end;
until ex;
end;
begin
Init;
Draw;
MainCycle;
if win then repeat until keypressed;
Close;
end.
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.