Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
metodichka_SI.doc
Скачиваний:
30
Добавлен:
23.02.2015
Размер:
2.05 Mб
Скачать

3 Задача

Найти путь с наименьшей стоимостью из пункта A в пункт B. Стоимость проезда из пункта A в пункт B и из пункта В в пункт А отличается.

Дополнительное условие:данные о графе считываются из текстового файла и хранятся в виде матрицы. Граф задаётся как матрица смежности.

#include <stdio.h>

#include <stdlib.h>

// количество вершин

int n;

// матрица смежности графа

int**G;

// массив пометок

int*M;

// длина пути

int npath;

// начальная вершина пути

int A;

// конечная вершина пути

int B;

// массив для номеров вершин, включённых в путь из A в B

int*path;

int main()

{

// загрузка данных из файла

Input();

// поиск в ширину: ищется самый дешёвый маршрут из A в B

FindPath(A,B);

printf("Path from A to B and back to A: ");

// вывод первой части пути на экран

PrintPath();

int cost = M[B];

// поиск в ширину: ищется самый дешёвый маршрут из B в A

FindPath(B,A);

// вывод второй части пути на экран

PrintPath();

cost += M[A];

// вывод стоимости

printf("\nIt costs %d\n",cost);

// освобождение памяти после использования всех нужных массивов

FreeMem();

return 0;

}

// функция выделения памяти под одномерный массив

void initarr(int*&A)

{

A = (int*)malloc(n*sizeof(int));

}

// функция выделения памяти под двумерный массив

void init2arr(int**&A)

{

A = (int**)malloc(n*sizeof(int*));

for (int i=0; i<n; i++)

A[i] = (int*)malloc(n*sizeof(int));

}

// функция освобождения памяти после использования двумерного массива

void free2arr(int**&A)

{

for (int i=0; i<n; i++)

free(A[i]);

free(A);

}

// функция освобождения памяти после использования всех нужных массивов

void FreeMem()

{

free2arr(G);

free(M);

free(path);

}

// функция загрузки данных из файла

void Input()

{

FILE*f;

// открытие текстового файла на считывание

f = fopen("graf.txt","r");

// считывание количества вершин графа

fscanf(f,"%d",&n);

// инициализация всех нужных массивов

init2arr(G);

initarr(M);

initarr(path);

int i,j;

// считывание матрицы смежности графа

for (i=0; i<n; i++)

for (j=0; j<n; j++)

fscanf(f,"%d",&G[i][j]);

// считывание начального и конечного пунктов маршрута

fscanf(f,"%d%d",&A,&B);

// для нумерации вершин с 0, а не с 1

A--; B--;

// закрытие файла

fclose(f);

}

// поиск в ширину: ищется самый дешёвый маршрут из A в B

void FindPath(int A,int B)

{

int i,j;

// инициализация массива пометок

for(i=0;i<n;i++)

M[i] = -1;

M[A] = 0;

int b = 1;

// пока в массиве пометок происходят изменения

while (b)

{

b = 0;

for (i=0; i<n; i++)

if (M[i] >= 0)

for (j=0; j<n; j++) if (i != j)

if (G[i][j])

// (в j-ю вершину пока пути не проложено)

if ((M[j] == -1) || (M[i] + G[i][j] < M[j]))

{

// ИЛИ (попасть в j-ю вершину из i-ой дешевле, чем способом, найденным до этого)

M[j] = M[i] + G[i][j];

b = 1;

}

}

// если в вершину B так и не дошли

if (M[B] == -1)

npath= 0;

else

{

// иначе проходим от B к A и записываем найденный путь в массив path

path[0] = B;

npath = 0;

j = B;

int d;

while (j != A)

{

i = 0;

d = 1;

while (d)

{

if (i != j)

if (G[i][j])

if (M[i] != -1)

d = (M[i] != M[j] - G[i][j]);

i++;

}

j = i-1;

npath++;

path[npath] = j;

}

}

}

// функция вывода пути на экран

void PrintPath()

{

for (int i=npath; i>=0; i--)

printf("%d ",path[i]+1);

}

Самостоятельная работа.

Изменить вторую задачу таким образом, чтобы вывести все возможные пути из пункта А в пункт В, не превышающие заданной стоимости.

Лабораторная работа №25

Метод с возвращением

Цель: использование метода с возвращением, нахождение единственного решения (если оно существует).

Методические рекомендации: лабораторная работа рассчитана на 2 часа и состоит из анализа одного разобранного задания и решения самостоятельной работы.

Для работы с данным методом предусмотрено 3 лабораторные работы и одно обязательное зачетное задание.

Необходимый уровень знаний:

  • работа с указателями;

  • работа с матрицами;

  • алгоритм поиска с возвращением.

Задача

Дана доска размером n x n. Вначале на поле с координатами x0, y0 помещается конь - фигура, которая перемещается по шахматным правилам. Задача заключается в поиске хотя бы одной последовательности ходов (если она существует), при которой конь точно один раз побывает на всех полях доски.

#include <stdio.h>

#include <stdlib.h>

// задание количества возможных ходов конем из данной клетки на бесконечном поле

intNSTEP= 8;

// задание массив для пометок: M[i][j] = номер хода, на котором конь попадет в клетку (i,j)

int**M;

// задание начального положения коня

int x0,y0;

// задание размера поля

intn;

// nn = n*n

int nn;

// = 1, если искомая матрица еще не найдена

intinprocess;

// ввод данных с экрана

void Input()

{

printf("n = ");

scanf("%d",&n);

nn = n*n;

printf("x0 = ");

scanf("%d",&x0);

printf("y0 = ");

scanf("%d",&y0);

// пользователь нумерует клетки шахматной доски начиная с единицы, компьютер // будет нумеровать с нуля

x0--;y0--;

}

// вывод результата на экран

void Output()

{

int i,j;

for (i=0; i<n; i++)

{

for (j=0; j<n; j++)

printf("%5d",M[i][j]);

printf("\n");

}

}

// выделение памяти под двумерный массив M

void InitMem()

{

M = (int**)malloc(n*sizeof(int*));

for (int i=0; i<n; i++)

M[i] = (int*)malloc(n*sizeof(int));

}

// освобождение памяти

voidFreeMem()

{

for (int i=0; i<n; i++)

free(M[i]);

free(M);

}

// присваивание каждому элементу массива M0

void InitM()

{

int i,j;

for (i=0; i<n; i++)

for (j=0; j<n; j++)

M[i][j] = 0;

}

// проверка, находится ли клетка (x,y) на полеnxn

int InRange(int x,int y)

{

return (x >= 0) && (x < n) && (y >= 0) && (y < n);

}

// ход коня из клетки (X,Y) в клетку (x,y)

void Move(int X,int Y,int&x,int&y,int k)

{

x = X;

y = Y;

// нумерация (k) - против часовой стрелки, от осиx

switch(k)

{

ход конем на две клетки вправо и на одну вверх

case 0: {x += 2; y -= 1; break;}

case 1: {x += 1; y -= 2; break;}

case 2: {x -= 1; y -= 2; break;}

case 3: {x -= 2; y -= 1; break;}

case 4: {x -= 2; y += 1; break;}

case 5: {x -= 1; y += 2; break;}

case 6: {x += 1; y += 2; break;}

case 7: {x += 2; y += 1; break;}

}

}

// перебор всех возможных вариантов очередного хода

void Step(int X,int Y,int h)

{

// если номер шага меньше n*n, то следует продолжать ходы

if (h <= nn)

{

int k;

int x,y;

// перебор всех возможных ходов конем из клетки (X,Y)

for (k=0; (k<NSTEP) && (inprocess); k++)

{

Move(X,Y,x,y,k);

// проверка, что после хода конь не оказался за пределами доски

if (InRange(x,y))

// проверка, что на данной позиции конь еще не побывал

if (!M[x][y])

{

// сохранение в матрицу Mномера хода

M[x][y] = h;

// рекурсивный вызов функцииStep(), совершение следующего хода

Step(x,y,h+1);

// если решение не найдено, стираем пометку с поля (x,y) (т.е. данный

// ход оказался ошибочным)

if (inprocess)

M[x][y] = 0;

}

}

}

// в противном случае процесс перебора нужно остановить, решение найдено

else

inprocess = 0;

}

int main()

{

// ввод данных с экрана

Input();

// выделение памяти под двумерный массив M

InitMem();

// присваивание каждому элементу массива M0

InitM();

// = 1, если искомая матрица еще не найдена

inprocess= 1;

// отмечаем, что в клетке (x0,y0) конь уже побывал

M[x0][y0] = 1;

запускаем функцию, рекурсивно выполняющую перебор ходов

Step(x0,y0,2); //

// вывод результата на экран

Output();

// освобождение памяти

FreeMem();

// ожидание ввода символа с клавиатуры

char c; scanf("%c",&c);

return0;

}

Самостоятельная работа.

Дана доска размером n x n. Вначале на поле с координатами x[i, j] (координаты задает пользователь) помещается конь - фигура, которая перемещается по шахматным правилам. Задача заключается в поиске хотя бы одной последовательности ходов (если она существует), при которой конь может перейти на поле с координатами x[k, m] (координаты задает пользователь).

Лабораторная работа №26

Метод с возвращением

Цель: использование метода с возвращением, нахождение всех решений (если они существует).

Методические рекомендации: лабораторная работа рассчитана на 2 часа и состоит из анализа одного разобранного задания.

Самостоятельная работа не предусмотрена.

Необходимый уровень знаний:

  • работа с указателями;

  • работа с матрицами;

  • алгоритм поиска с возвращением.

Задача

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

#include <stdio.h>

#include <stdlib.h>

#define N 8

//размер доски - N x N

int*q,*horiz,*diag1m,*diag2;

intinprocess;

/*

q[i] – позиция столбца, где находится ферзь, стоящий наi-й горизонтали

horiz[i]=1 <=>i-тая горизонталь занята

diag1m- диагонали, параллельные главной,diag1m[N-1] - главная диагональ

Нумерация (для N=4):

3210

4321

5432

6543

diag1m[i]=1 <=>i-тая диагональ, параллельная главной, (далее - диагональ-1) занята

diag2 - диагонали, параллельные побочной,diag2[N-1] - побочная диагональ

Нумерация:

0123

1234

2345

3456

diag2[i]=1 <=>i-тая диагональ, параллельная побочной, (далее - диагональ-2) занята

*/

intmain()

{

// выделение памяти для всех используемых массивов

InitMem();

// заполнение массивов horiz,diag1mиdiag2 нулями

InitFill();

//=1 <=> решение еще не найдено

inprocess= 1;

//запуск рекурсивной функции с нулевого столбца

Step(0);

// вывод доски на экран: 0 - пустое поле, 1 - на поле стоит ферзь

Output();

// освобождение памяти

FreeMem();

return0;

}

// функция постановки ферзя на клетку (i,j) (находящуюся наi-той строке иj-том столбце)

void put(int i,int j,int k)

{

q[i] = j;

// если k=1, то мы отмечаем, чтоi-тая горизонталь, (N-1-j+i)-тая диагональ-1 и (i+j)-тая

// диагональ-2 теперь находятся под боем,

// иначе отмечаем, что эта горизонталь и эти диагонали освобождаются

horiz[i] = k;

diag1m[N-1-j+i] = k;

diag2[i+j] = k;

}

//=1 <=> можно поставить ферзя на клетку (i,j)

int canstay(int i,int j)

{

// проверяем, не находятся ли соответствующие горизонталь и диагонали под боем

return (!horiz[i] && !diag1m[N-1-j+i] && !diag2[i+j]);

}

// функция для постановки ферзя на h-ый столбец (нумерация с нуля)

void Step(int h)

{

// если номер столбца не превысил (N-1), то продолжаем поиск решения

// (нумерация столбцов с нуля)

if (h < N)

// просмотр всех строк на наличие решения

for (int i=0; (i<N) && inprocess; i++)

// проверка, что мы можем ставить ферзя в клетку (i,h)

if (canstay(i,h))

{

put(i,h,1);

// поиск позиции для следующего ферзя

Step(h+1);

// если решение не найдено, то освобождаем клетку

if (inprocess)

put(i,h,0);

}

else{}

// иначе решение найдено

else

inprocess= 0;

}

// функция вывода доски на экран: 0 - пустое поле, 1 - на поле стоит ферзь

void Output()

{

int i,j;

for (i=0; i<N; i++)

{

for (j=0; j<N; j++)

if (j == q[i])

printf("1 ");

else

printf("0 ");

printf("\n");

}

}

// функция выделения памяти под массив из nэлементов типаint

void initarr(int*&A,int n)

{

A = (int*)malloc(n*sizeof(int));

}

// функция выделения памяти для всех используемых массивов

void InitMem()

{

initarr(horiz,N);

initarr(diag1m,2*N-1);

initarr(diag2,2*N-1);

initarr(q,N);

}

// функция освобождение памяти

voidFreeMem()

{

free(horiz);

free(diag1m);

free(diag2);

free(q);

}

// функция заполнения массивов horiz,diag1mиdiag2 нулями

void InitFill()

{

int i;

for (i=0; i<N; i++)

horiz[i] = 0;

for (i=0; i<2*N-1; i++)

{

diag1m[i] = 0;

diag2[i] = 0;

}

}

Лабораторная работа №27

Метод с возвращением

Цель: использование метода с возвращением, нахождение оптимального решения по заданному критерию.

Методические рекомендации: лабораторная работа рассчитана на 2 часа и состоит из анализа одного разобранного задания.

Самостоятельная работа не предусмотрена.

Необходимый уровень знаний:

  • работа с указателями;

  • работа с матрицами;

  • алгоритм поиска с возвращением.

Задача

Имеется n мужчин и n женщин. Требуется разделить их на пары, которые заключают между собой браки. Каждая из n женщин выбирает мужчин в порядке предпочтения, от мужчины, которому оказывается наибольшее предпочтение (его ранг равен 1), до того, которому - наименьшее (его ранг равен n). Информация об этих предпочтениях дана в виде матрицы и хранится в текстовом файле. В том же файле находится аналогичная информация для предпочтений мужчин. Решением является выбор пар, которые должны удовлетворять условию стабильности (все браки должны быть стабильными).

Брак между m и w считается нестабильным, если выполняется одно из двух условий:

  • существует женщина w1, которая у мужчины m имеет большее предпочтение, чем женщина w и у женщины w1 мужчина m имеет большее предпочтение, чем ее муж;

  • существует мужчина m1, который у женщины w имеет большее предпочтение, чем мужчина m и у мужчины m1 женщина w имеет большее предпочтение, чем его жена.

Необходимо вывести все решения, а также оценки оптимальности каждого решения для мужчин и для женщин.

Оценка оптимальности для женщин определяется как сумма рангов их мужей.

Аналогично определяется оценка оптимальности решения для мужчин.

#include <stdio.h>

#include <stdlib.h>

// количество пар

int n;

// массивы предпочтений

int**W,**M;

// y[i] - мужчина, состоящий в браке с i-той женщиной

int*y;

// x[i] - женщина, состоящая в браке с i-тым мужчиной

int*x;

// Wr[w][m] - ранг m-того мужчины у w-женщины

// (Wr[w][m]=0 <=> женщина w отдает мужчине m наибольшее предпочтение)

int**Wr;

// Mr[m][w] - ранг w-женщины у m-того мужчины

int**Mr;

// функция выделения памяти под одномерный массив из n элементов типа int

void initarr(int*&A)

// функция выделения памяти под двумерный массив n x n

void init2arr(int**&A)

// функция выделения памяти под все используемые массивы

voidInitMem()

// функция освобождения памяти, отведенной под двумерный массив

void free2arr(int**&A)

// функция освобождения памяти, отведенной под все используемые массивы

voidFreeMem()

// функция заполнения массивов x[] и y[] -1 (x[m]=-1 <=> m пока не состоит в браке)

voidInitFill()

// функция считывания из текстового файла fдвумерный массивA

void freadarr(FILE*&f,int**A)

// функция загрузки n и двух матриц предпочтений из файла

voidInput()

// функция заключение брака между w и m

void put(int w,int m,int k)

// функция проверки стабильности браков

int AllStable()

// функция вывода решения на экран

voidOutput()

// функция выбора мужчины для w-ой женщины

void Step(int w)

// функция выделения памяти под одномерный массив из n элементов типа int

void initarr(int*&A)

{

A = (int*)malloc(n*sizeof(int));

}

// функция выделения памяти под двумерный массив n x n

void init2arr(int**&A)

{

A = (int**)malloc(n*sizeof(int*));

for (int i=0; i<n; i++)

initarr(A[i]);

}

// функция выделения памяти под все используемые массивы

void InitMem()

{

init2arr(W);

init2arr(M);

init2arr(Wr);

init2arr(Mr);

initarr(y);

initarr(x);

}

// функция освобождения памяти, отведенной под двумерный массив

void free2arr(int**&A)

{

for (int i=0; i<n; i++)

free(A[i]);

free(A);

}

// функция освобождения памяти, отведенной под все используемые массивы

void FreeMem()

{

free2arr(W);

free2arr(M);

free2arr(Wr);

free2arr(Mr);

free(y);

free(x);

}

// функция заполнения массивов x[] и y[] -1 (x[m]=-1 <=> m пока не состоит в браке)

void InitFill()

{

for (int i=0; i<n; i++)

{

y[i] = -1;

x[i] = -1;

}

}

// функция считывания из текстового файла fдвумерный массивA

void freadarr(FILE*&f,int**A)

{

int r;

int i,j;

for (i=0; i<n; i++)

for (j=0; j<n; j++)

{

fscanf(f,"%d",&r);

A[i][j] = r-1;

}

}

// функция загрузки n и двух матриц предпочтений из файла

void Input()

{

FILE*f;

// открытие текстового файла на чтение

f = fopen("marriage.in","r");

fscanf(f,"%d",&n);

// выделение памяти под все используемые массивы

InitMem();

// считывание из текстового файла f двумерного массива W

freadarr(f,W);

// считывание из текстового файла f двумерного массива M

freadarr(f,M);

// закрытие файла

fclose(f);

}

// функция заключение брака между w-ой женщиной и m-м мужчиной

void put(int w,int m,int k)

{

// если брак заключается, то ставим в соответствие w и m друг другу

if (k)

{

x[m] = w;

y[w] = m;

}

// если брак расторгается, то отмечаем, что w и m теперь single

else

{

x[m] = -1;

y[w] = -1;

}

}

//=1 <=> брак между w и m стабилен

int stable(int w,int m)

{

// предполагаем, что брак стабилен

int yes = 1;

int i = 0;

int m1 = W[w][i];

// проверяем, что жена не уйдет налево

// т.е. перебираем всех мужчин, имеющим у w больший приоритет, чем ее

// предполагаемый муж m

while((m1 !=m) &&yes)

{

// проверка останавливается либо при исчерпании этих мужчин, либо при

// обнаружении нестабильности брака

if(x[i] != -1)

yes = (Mr[m1][w] > Mr[m1][x[m1]]);

i++;

m1 = W[w][i];

}

i = 0;

int w1 = M[m][i];

// проверяем, что муж не уйдет налево

// т.е. перебираем всех женщин, имеющим у m больший приоритет, чем его

// предполагаемая жена w

while((w1 !=w) &&yes)

{

if (y[w1] != -1)

yes = (Wr[w1][m] > Wr[w1][y[w1]]);

i++;

w1 = M[m][i];

}

returnyes;

}

// функция проверки стабильности браков

int AllStable()

{

//предполагаем, что это так

int yes = 1;

int w;

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

for (w=0; (w<n) && yes; w++)

yes = stable(w,y[w]);

return yes;

}

// функция вывода решения на экран

void Output()

{

int m;

// rm и rw - оценки оптимальности полученного решения для мужчин и женщин

// соответственно

int rm = 0;

// чем меньше rw, тем оптимальнее полученное решение для женщин

int rw = 0;

for (m=0; m<n; m++)

{

printf("%d ",x[m]+1);

rm += Mr[m][x[m]];

rw += Wr[x[m]][m];

}

// вывод оценок оптимальности после самого решения, через разделители

printf("|%3d|%3d\n",rm+n,rw+n);

}

// функция выдбора мужчины для w-ой женщины

void Step(int w)

{

//если еще не все женщины вышли замуж, то продолжаем поиск решения

if (w < n)

{

int m;

// перебор по рангу i мужчины m у женщины w

for (int i=0; i<n; i++)

// проверка, что m холост

if (x[W[w][i]] == -1)

{

m = W[w][i];

// предварительная проверка, что на данном этапе при уже заключенных

// браках этот брак стабилен

if (stable(w,m))

{

// предварительная проверка, что на данном этапе при уже

// заключенных браках этот брак стабилен

put(w,m,1);

// рекурсивный вызов функции Step() для (w+1)-женщины

Step(w+1);

// заключаем брак между w и m

put(w,m,0);

}

else{}

}

else{}

}

// иначе проверяем полученное решение на "устойчивость"

else

if (AllStable())

// в случае полной стабильности решения выводим его на экран

Output();

else{}

}

// формирование матриц рангов Wr и Mr

void FormWrMr()

{

int m,w,i;

for (m=0; m<n; m++)

for (i=0; i<n; i++)

Mr[m][M[m][i]] = i;

for (w=0; w<n; w++)

for (i=0; i<n; i++)

Wr[w][W[w][i]] = i;

}

intmain()

{

// загрузка n и двух матриц предпочтений из файла

Input();

// формирование матриц рангов Wr и Mr

FormWrMr();

// заполнение массивов x[] и y[] -1 (x[m]=-1 <=> m пока не состоит в браке)

InitFill();

// подбор мужчины для 0-женщины, в теле этой функции рекурсивно запускается

// подбор для 1-женщины и т.д.

Step(0);

// освобождение памяти, отведенной под все используемые массивы

FreeMem();

return 0;

}

Лабораторная работа №28

Элементарные методы сортировки

Цель: закрепление на практике навыков для работы с некоторыми элементарными методами сортировки.

Методические рекомендации: лабораторная работа рассчитана на 2 часа и состоит из анализа трех разобранных заданий.

Самостоятельной работы не предусмотрена.

Для работы с элементарными методами сортировки предусмотрено 3 лабораторные работы и одно обязательное зачетное задание.

Необходимый уровень знаний:

  • работа с указателями;

  • работа с функциями.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]