быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
1

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

29.07.2011, 21:59. Показов 8965. Ответов 96

Author24 — интернет-сервис помощи студентам
Друзья!
Ввиду возникшей необходимости мной был написан класс "рекурсивный обход матрицы"; Теперь задачи на такую тематику будут решаться легко и просто. С меня интерфейс, с вас- мозги.

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

................................................................................ ....
1 Попытка к бегству

Время на тест - 3 секунды.


Узник пытается бежать из замка, который состоит из MN квадратных комнат, расположенных в виде прямоугольника M?N. Между любыми двумя соседними комнатами есть дверь , однако некоторые комнаты закрыты и попасть в них нельзя. В начале узник находится в угловой комнате и для спасения ему надо попасть в противоположную угловую комнату. Времени у него немного, всего он может побывать не более, чем в M+N-1 комнате, включая начальную и конечную комнату на своем пути, то есть с каждым переходом в соседнюю комнату расстояние до выхода из замка должно уменьшаться. От вас требуется найти количество различных маршрутов, ведущих к спасению.
Формат входных данных

Первая строчка входных данных содержит натуральные числа M и N, не превосходящих 1000. Далее идет план замка в виде M строчек из N символов в каждой. Один символ соответствует одной комнате: если символ равен 1, то в комнату можно попасть, если он равен 0, то комната закрыта. Первоначальное положение узника - левый нижний угол (первый символ последней строки), выход находится в правом верхнем углу (последний символ первой строки, оба этих символа равны 1).
Формат выходных данных

Программа должна напечатать количество маршрутов, ведущих узника к выходу и проходящих через M+N-1 комнату, или слово impossible, если таких маршрутов не существует.

Входные данные подобраны таким образом, что искомое число маршрутов не превосходит 2.000.000.000.
Пример

Входные данные

3 5
11111
10101
11111

Выходные данные

3

Входные данные

3 5
11101
10101
10101

Выходные данные

impossible
................................................................................ ...

ОК, ну что ж, не будем размениваться по мелочам. Я думаю если мы найдём цепочки клеток, по которым из левого нижнего угла можно добраться до правого верхнего, количество цепочек вы найдёте сами.

...Кстати, вот эти цепочки:
(4 0) (3 0) (2 0) (1 0) (0 0) (0 1) (0 2) (0 3) (0 4)
(4 0) (3 0) (2 0) (2 1) (2 2) (1 2) (0 2) (0 3) (0 4)
(4 0) (3 0) (2 0) (2 1) (2 2) (2 3) (2 4) (1 4) (0 4)
(4 0) (4 1) (4 2) (3 2) (2 2) (1 2) (0 2) (0 3) (0 4)
(4 0) (4 1) (4 2) (3 2) (2 2) (2 3) (2 4) (1 4) (0 4)
(4 0) (4 1) (4 2) (4 3) (4 4) (3 4) (2 4) (1 4) (0 4)

................................................................................ ....

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

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int M, N;
 M= N= 5;
 
 
 //Массив 
 int** array_osn= new int* [M] ;
 
 //ВЫделили память под него и заполнили
 for (int i= 0; i< M; i++) {
  array_osn[i]= new int[N];
 }
 for (int i= 0; i< M; i++) {
  for (int j= 0; j< N; j++) {
   array_osn [i] [j]= 1;
  }
 }
  array_osn [1] [3]= array_osn [3] [3]= array_osn [3] [1]= array_osn [1] [1]= 0 ;
 
 
 rek_obhod_matr<int> obhod (array_osn, M, N, 4, 0/*и это не все параметры*/)
Пока всё просто. А теперь пошли трудности. Плюсом к перечисленным параметрам в конструктор вы передаёте три СОБСТВЕННЫХ функции.

А взамен получаете вектор векторов пар элементов типа int, каждая пара- координаты очередной точки. Ну то есть вот такую штуку получаете:
C++
1
vector <vector <pair<int, int> > > puti;
(Кстати, размер этого ветора и будет количенство путей, в нашем случае 6, угу?)

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +++

Сосредоточимся на функциях- членах класса
Смотрите. Если мы "стоим" в некоторой клетке, объект, созданный нами называется obhod, то её координаты текущие. Их можно найти с помощью функций-членов:

C++
1
2
int obhod.get_i_tek(); 
int obhod.get_j_tek();
\\\\\\\\\\\\\\\\

Вернёмся к задаче. Представьте себе, что мы каким-то образом (пока неважно, каким, объяснение позже) "добрались" до клетки, например (1, 0) и стоим в ней. Вопрос: какой путь мы прошли? Правильно, вот он: (4, 0) (3, 0) (2, 0)

И возвращается он такой функцией- членом:
C++
1
vector< pair<int, int> > set_chto_proshli ();
...А если мы будем стоять, например в точке (2, 2), то вернётся путь
(4, 0)(3, 0)(2, 0)(2, 1) или (4, 0) (4, 1) (4, 2) (3, 2)

Внимание! Координаты текущей клетки в пройденныё путь не входят!

\\\\\\\\\\\\\\\\

Ещё один вектор, который может нам пригодиться- вектор точек, куда мы можем пойти. Допустим, мы стоим в точке (2, 0). Можем пойти в две точки: (1, 0) или (2, 1)
Вектор этих пар вернёт нам функция-член
C++
1
vector< pair<int, int> > get_kuda_poidom ();
\\\\\\\\\\\\\\\\

Ещё две полезных функции-члена могут нам пригодиться:
Преобразования типа, эта херь позволит перегрузить оператор [][]
Это я сам придумал подачи ребят
C++
1
operator T**() {return matrix;};
Так, а эта функция просто возвращает результат
Это возвращает вектор найденнных путей клеток
C++
1
vector <vector <pair<int, int> > > set_puti () {return puti;}
Ну можно ещё что-нибудь будет добавить при необходимости. Например, возврат количества столбцов, кому охота уж

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++++

А теперь сосредоточимся на авторских функциях.

111111111111111

Первая функция-предикат, вот её прототип:
C++
1
2
template <class T>
bool _poisk_kletok_ (rek_obhod_matr<int>* source, int i_pot, int j_pot);
Она принимает указатель на объект и координаты точки, куда ПОТЕНЦИАЛЬНО можно шагнуть или прыгнуть, кому как охота. Наша задача в этой функции решить подходит ли эта точка для прыжка или нет. Понятное дело, что точка для прыжка должна располагаться рядом с текущей, да не просто рядом а справа или сверху. То есть так:

C++
1
2
3
4
5
6
7
8
9
10
11
12
template <class T>
bool _poisk_kletok_ (rek_obhod_matr<int>* source, int i_pot, int j_pot) {
 
 //Это вот потенциальная точка справа расположена
 if((i_pot== (*source).get_i_tek())&&(j_pot== ((*source).get_j_tek()+ 1)))
  //Тут щас будет код 
 
 //А эта сверху
 if((j_pot== (*source).get_j_tek())&&(i_pot== ((*source).get_i_tek()- 1)))
  //Тоже щас будет код
 
}
ОК, кроме того в клетке с координатами (i_pot, j_pot) должна быть единица

C++
1
2
3
4
5
6
7
8
9
10
11
template <class T>
bool _poisk_kletok_ (rek_obhod_matr<int>* source, int i_pot, int j_pot) {
  if((i_pot== (*source).get_i_tek())&&(j_pot== ((*source).get_j_tek()+ 1)))
  if ((*source)[i_pot][j_pot]== 1) {  
   return true;
  }
 if((j_pot== (*source).get_j_tek())&&(i_pot== ((*source).get_i_tek()- 1)))
  if ((*source)[i_pot][j_pot]== 1)  
   return true;
 return false;
}
Вот мы и написали первую функцию предикат

222222222222222222222

Вторая функция-предикат. Необходима для того, чтобы определить- очередной путь закончился или нет? А применительно к нашей задаче- создана ли ЛЮБАЯ из цепочек путей?
Прототип у неё попроще будет, принимает просо указатель на объект

C++
1
2
template <class T>
bool mozhno_pribavlat_put_ili_net (rek_obhod_matr<int>* source);
Внимание! Путь считается пройденным, если мы "стоим" в некоторой клетке, и она- конец пути.
!!!Помним, что она пока ещё не занесена в пройденный путь!

C++
1
2
3
4
5
6
7
template <class T>
bool mozhno_pribavlat_put_ili_net (rek_obhod_matr<int>* source) {
 //Тут всё просто. Если текущие координаты 0, 4 значит мы в конце пути
 if (!(*source).get_i_tek() && (*source).get_j_tek()== 4) 
  return true; 
 return false;            
}
По-моему ничё сложного

3333333333333333333333333

А третья функция изменения. Она нужна для изменения содержания клетки. В данном примере она совсем не нужна. Так как содержимое клеток мы не меняем. Но ниже я приведу пример, когда она нужна. Прототип:
C++
1
2
template <class T>
void izmenenia (rek_obhod_matr<int>* source);
Вот и всё. Теперь скомпонуем всю эту херь в один код. И да, вот окончательный
вариант прототипа конструктора
C++
1
2
3
4
5
6
7
8
9
//Конструктор, принимает такие парамеры: указатель на матрицу,
  //количество строк, количество столбцов
  //начало (строку, столбец)
  //Функцию-предикат отвечающую за то, на какую точку будет совершён переход (прыжок)
  //Функцию- предикат, определяющую, найден ли очередной путь или нет
  //и функцию, меняющую (или не меняющую) матрицу
  rek_obhod_matr(T**, int, int,int, int,  bool(*)(rek_obhod_matr<int>* source, int, int),\
                 bool (*) (rek_obhod_matr<int>* source),\
                 void (*)(rek_obhod_matr<int>* source));
А вот весь код будет таким, вывод прилагается
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#include <iostream>
#include <windows.h>
using namespace std;
 
 
#include "rek_obhod_matr.h" 
 
 
 
 
//Первая авторская функция-предикат
template <class T>
bool _poisk_kletok_ (rek_obhod_matr<int>* source, int i_pot, int j_pot) {
 if((i_pot== (*source).get_i_tek())&&(j_pot== ((*source).get_j_tek()+ 1)))
  if ((*source)[i_pot][j_pot]== 1) {  
   return true;
  }
 if((j_pot== (*source).get_j_tek())&&(i_pot== ((*source).get_i_tek()- 1)))
  if ((*source)[i_pot][j_pot]== 1)  
   return true;
 return false;
}
 
//Вторая авторская функция-предикат
template <class T>
bool mozhno_pribavlat_put_ili_net (rek_obhod_matr<int>* source) {
 if (!(*source).get_i_tek() && (*source).get_j_tek()== 4) 
  return true; 
 return false;            
}
 
 
//И третья функция называется
template <class T>
void izmenenia (rek_obhod_matr<int>* source) {}
 
 
 
int main() {
 SetConsoleCP(1251);
 SetConsoleOutputCP(1251);
 
 int M, N;
 M= N= 5;
 
 
 //Массив тот самый
 int** array_osn= new int* [M] ;
 
 for (int i= 0; i< M; i++) {
  array_osn[i]= new int[N];
 }
 for (int i= 0; i< M; i++) {
  for (int j= 0; j< N; j++) {
   array_osn [i] [j]= 1;
  }
 }
 array_osn [1] [3]= array_osn [3] [3]= array_osn [3] [1]= array_osn [1] [1]= 0 ;
 
 
 //ВЫведем его
 printf ("сам массив:\n");
 for (int i= 0; i< M; i++) {
  for (int j= 0; j< N; j++)
   printf ("%d ", array_osn[i][j]);
  printf ("\n");
 };
 
 
 rek_obhod_matr<int> obhod (array_osn, M, N, 4, 0,\
                            _poisk_kletok_<int>,\
                            mozhno_pribavlat_put_ili_net<int>,\
                            izmenenia<int>);
 
 //А здесь мы венули решение
 vector <vector <pair<int, int> > > puti= obhod.set_puti ();
 
 
 
 
 //Тут уже изгаляюсь вывожу пути
 printf ("\nрешение:\n");
 int k= 0;
 for (int i= 0; i< obhod.set_puti().size(); i++) {
  for (int j= 0; j< 9; j++) {
   printf ("(%d %d) ", obhod.set_puti()[i][j].first, obhod.set_puti()[i][j].second);
   if ((!((k+1)%9))&& k) {
    printf ("\n");
   }
   k++;
  }
 }
 
 
 getchar ();
 return 0;
}
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ $$$$$

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

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#include <iostream>
#include <windows.h>
using namespace std;
 
 
#include "rek_obhod_matr.h" 
 
 
 
 
 
//Вот эта та самая первая функция, над которой полоьзователю придётся покорпеть.
//Принимает указатель на объект координаты точки на которую якобы надо делать ход
//потенциальные то есть i_pot и j_pot
template <class T>
bool _poisk_kletok_ (rek_obhod_matr<int>* source, int i_pot, int j_pot) {
 //ПОехали условие кропать
 if (!(*source)[i_pot][j_pot]&& !(!i_pot&&!j_pot)) {
 
  //Потенциальая клетка находится над текущей клеткой
  if ((i_pot== (*source).get_i_tek()- 1)&& (j_pot== (*source).get_j_tek())) {
    if (!j_pot) {
     return true;
    }
    else if ((*source)[i_pot+ 1][j_pot- 1]) {
     return true;
    };
  }  
 
  //Потенциальная клетка находится под текущей клеткой
  if ((i_pot== (*source).get_i_tek()+ 1)&& (j_pot== (*source).get_j_tek())) {
   if (j_pot== (9- 1))
    return true;
   else if ((*source)[i_pot][j_pot+ 1]) 
    return true;
  }
  //Потенциальная клетка находтся слева от текущей
  if ((j_pot== (*source).get_j_tek()- 1)&& (i_pot== (*source).get_i_tek())) {
   if (i_pot== (6- 1))
    return true;
   else if ((*source)[i_pot+ 1][j_pot+ 1]) { 
    return true;
   }
 }
  //Потенциальная клетка находтся справа от текущей
  if ((j_pot== (*source).get_j_tek()+ 1)&& (i_pot== (*source).get_i_tek())) {
   if (!i_pot)
    return true;
   else if (((*source)[i_pot- 1][j_pot- 1])||(!(i_pot- 1)&&!(j_pot- 1))) { 
    return true;
   }
  } 
 }
 
 return false;
}
 
//Тут просто
template <class T>
bool mozhno_pribavlat_put_ili_net (rek_obhod_matr<int>* source) {
 if (((*source).set_chto_proshli()).size()== 53) 
  return true; 
 return false;            
}
 
 
//И третья функция называется "izmenenia"
//Если наша задача стоит изменить матрицу (заполнить по спирали элементами и прочая)
//То эта функция должна изменить клетку, которую мы РЕШИЛИ ДОБАВИТЬ В ПУТЬ
//То есть речь идёт о клетке с текущими координатами
template <class T>
void izmenenia (rek_obhod_matr<int>* source) {
 if (!(*source).get_i_tek()&& !(*source).get_j_tek()) 
  (*source)[(*source).get_i_tek()][(*source).get_j_tek()]= 0;
 else {
  (*source)[(*source).get_i_tek()][(*source).get_j_tek()]=\
  (*source)[(*source).set_chto_proshli().back().first][(*source).set_chto_proshli().back().second]+ 1;
 }
}
 
 
 
int main() {
 SetConsoleCP(1251);
 SetConsoleOutputCP(1251);
 
 int M, N;
 M= 6;
 N= 9;
 
 
 //Массив тот самый
 int** array_osn= new int* [M] ;
 
 for (int i= 0; i< M; i++) {
  array_osn[i]= new int[N];
 }
 for (int i= 0; i< M; i++) {
  for (int j= 0; j< N; j++) {
   array_osn [i] [j]= 0;
  }
 }
 
 
 //ВЫведем его
 printf ("Вывод \"заполнение матрицы по спирали\"\n");
 printf ("сам массив:\n");
 for (int i= 0; i< M; i++) {
  for (int j= 0; j< N; j++)
   printf ("%d ", array_osn[i][j]);
  printf ("\n");
 };
 
 rek_obhod_matr<int> obhod (array_osn, M, N, 0, 0,\
                            _poisk_kletok_<int>,\
                            mozhno_pribavlat_put_ili_net<int>,\
                            izmenenia<int>);
 vector <vector <pair<int, int> > > puti= obhod.set_puti ();
 
 vector <pair<int, int> > put= obhod.set_chto_proshli();
 
 printf ("\nрешение:\n");
 int k= 0;
 for (int i= 0; i< put.size(); i++) {
  printf ("(%d %d %d) ", put[i].first, put[i].second, obhod [put[i].first][put[i].second]);
  if ((!((k+1)%9))&& k) {
   printf ("\n");
  }
  k++;
 }
 getchar ();
 return 0;
}
И последняя задача такая: определить все ходы белой шашки.
Значит, у меня белая шашка это единичка, чёрные двойки, остальные ноли. Всё то же самое. Два предиката, пустое изменение, массив, создание объекта и любование результатом.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#include <iostream>
#include <windows.h>
using namespace std;
 
 
#include "rek_obhod_matr.h" 
//Это определение ходов белой шашки
 
 
 
 
template <class T>
bool _poisk_kletok_ (rek_obhod_matr<int>* source, int i_pot, int j_pot) {
 
 
 vector< pair<int, int> > chto_proshli= (* source).set_chto_proshli (); 
 pair <int, int> para (i_pot, j_pot);
 vector< pair<int, int> >:: iterator it;
 it= find (chto_proshli.begin(), chto_proshli.end(), para);
 if (it== chto_proshli.end()) {
 
 
 //Срубаем вправо вниз
 if ((((*source).get_i_tek()+ 2)== i_pot)&& (((*source).get_j_tek()+ 2)== j_pot)&&(!(*source)[i_pot][j_pot])&&\
  ((*source)[(*source).get_i_tek()+ 1][(*source).get_j_tek()+ 1]== 2)) {
  if ((*source)[i_pot- 1][j_pot- 1]== 2)
   if ((*source).set_chto_proshli().size()== 2)
    if (abs((*source).set_chto_proshli()[0].first- (*source).set_chto_proshli()[1].first)== 2)
     return true; 
    else return false;
   else return true; 
 }
 //Срубаем влево вниз
 if ((((*source).get_i_tek()+ 2)== i_pot)&& (((*source).get_j_tek()- 2)== j_pot)&&(!(*source)[i_pot][j_pot])&&\
  ((*source)[(*source).get_i_tek()+ 1][(*source).get_j_tek()- 1]== 2)) {
  if ((*source)[i_pot- 1][j_pot+ 1]== 2)
   if ((*source).set_chto_proshli().size()== 2)
    if (abs((*source).set_chto_proshli()[0].first- (*source).set_chto_proshli()[1].first)== 2)
     return true; 
    else return false;
   else return true; 
 } 
 
 //Срубаем влево вверх
 if ((((*source).get_i_tek()- 2)== i_pot)&& (((*source).get_j_tek()- 2)== j_pot)&&(!(*source)[i_pot][j_pot])&&\
  ((*source)[(*source).get_i_tek()- 1][(*source).get_j_tek()- 1]== 2)) {
  if ((*source)[i_pot+ 1][j_pot+ 1]== 2)
   if ((*source).set_chto_proshli().size()== 2)
    if (abs((*source).set_chto_proshli()[0].first- (*source).set_chto_proshli()[1].first)== 2)
     return true; 
    else return false;
   else return true; 
 }
 
 //Срубаем вправо вверх
 if ((((*source).get_i_tek()- 2)== i_pot)&& (((*source).get_j_tek()+ 2)== j_pot)&&(!(*source)[i_pot][j_pot])&&\
  ((*source)[(*source).get_i_tek()- 1][(*source).get_j_tek()+ 1]== 2)) {
  if ((*source)[i_pot+ 1][j_pot- 1]== 2)
   if ((*source).set_chto_proshli().size()== 2)
    if (abs((*source).set_chto_proshli()[0].first- (*source).set_chto_proshli()[1].first)== 2)
     return true; 
    else return false;
   else return true; 
 }  
 
 
 //Ходим влево вверх
 if ((((*source).get_i_tek()- 1)== i_pot)&& (((*source).get_j_tek()- 1)== j_pot) && ((*source)[i_pot][j_pot]== 0)) {
  if (!(*source).set_chto_proshli().size()) {
   return true; 
  }
 }
 //Ходим вправо вверх
 if ((((*source).get_i_tek()- 1)== i_pot)&& (((*source).get_j_tek()+ 1)== j_pot) && ((*source)[i_pot][j_pot]== 0)) {
  if (!(*source).set_chto_proshli().size()) {
   return true; 
  }
 }
} 
 
 return false;
}
 
 
//Эта будет вторая функция, над которой придётся покорпеть
//Ну то есть тупо: завершён очередной обход или нет
template <class T>
bool mozhno_pribavlat_put_ili_net (rek_obhod_matr<int>* source) {
 if(((*source).get_kuda_poidom().size())== 0)
   return true; 
 return false;            
}
 
 
template <class T>
void izmenenia (rek_obhod_matr<int>* source) {}
 
 
 
int main() {
 SetConsoleCP(1251);
 SetConsoleOutputCP(1251);
 
 int M, N;
 M= 8;
 N= 8;
 
 
 //Массив тот самый
 int** array_osn= new int* [M] ;
 
 for (int i= 0; i< M; i++) {
  array_osn[i]= new int[N];
 }
 for (int i= 0; i< M; i++) {
  for (int j= 0; j< N; j++) {
   array_osn [i] [j]= 0;
  }
 }
 
 array_osn [2][1]= array_osn [2][3]=array_osn [4][3]= 2;
 array_osn [5][2]= 1;
 
 //ВЫведем его
 printf ("сам массив:\n");
 for (int i= 0; i< M; i++) {
  for (int j= 0; j< N; j++)
   printf ("%d ", array_osn[i][j]);
  printf ("\n");
 };
 
 
 
 rek_obhod_matr<int> obhod (array_osn, M, N, 5, 2,\
                            _poisk_kletok_<int>,\
                            mozhno_pribavlat_put_ili_net<int>,\
                            izmenenia<int>);
 vector <vector <pair<int, int> > > puti= obhod.set_puti ();
 
 vector <pair<int, int> > put= obhod.set_chto_proshli();
 
 printf ("\nрешение:\n");
 for (int i= 0; i< obhod.set_puti().size(); i++) { 
  for (int j= 0; j< obhod.set_puti()[i].size(); j++)  
   printf ("(%d %d) ", obhod.set_puti()[i][j].first, obhod.set_puti()[i][j].second);
  printf ("\n");
 }
 getchar ();
 return 0;
}

В классе есть недостатки, так я например не уверен, что всегда надо передавать матрицу в него и делать там копию. Но я для надёжности передаю всё же. В общем, правьте, уточняйте тестируйте. Говорите чё не так, буду исправлять. РАспространяется по лицензии GPL
Миниатюры
предлагаю людям класс "рекурсивный обход матрицы" для решения задач на такую тематику   предлагаю людям класс "рекурсивный обход матрицы" для решения задач на такую тематику   предлагаю людям класс "рекурсивный обход матрицы" для решения задач на такую тематику  

0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
29.07.2011, 21:59
Ответы с готовыми решениями:

Предлагаю людям класс для написания специфических снимков системы
Задачи, преследуемые этим классом минимальные, но тем не менее. Делать снимки системы привязываясь...

предлагаю людям класс "каждому потоку- своё окно" для тестирования многопоточных приложений.
Друзья! То есть если вы разрабатывает многопоточные приложения и закалебались смотреть, что тот или...

Предлагаю заголовочный файл с реализацией функций и классов, необходимых для решения задач по комбинаторике
kombinatorika.h Этот заголовочный файл подключается для работы с комбинаторикой. В нём...

Рекурсивный обход матрицы
#include &lt;iostream&gt; #include &lt;queue&gt; using namespace std; class cord { int x; int...

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

96
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
30.07.2011, 19:02  [ТС] 41
Author24 — интернет-сервис помощи студентам
Цитата Сообщение от Evg Посмотреть сообщение
Возьми более сложную задачу. На клетчатой прямоугольной доске расставлены цифры. Требуется пройти из левого угла в правый, чтобы путь при этом был не более стольки-то, но при этом чтобы сумма чисел по пути следования была максимальная, при этом если по одной клетке проходим два раза, то второй раз число не засчитывается

Если на прямоугольной доске нарисован лабиринт (клетка занята или свободна). Надо найти из него выход (как усложнение - выход по самому короткому пути)
ОК, это действенный способ окатить меня ледяным душем. Конкретизируй условия не до конечных, но: угол левый верхний или нижний (или любой, то же касается и правого угла)? Ограничение я так понял любое (будет рандомное)... вроде ничё не пропустил. Да, числа рандомные тоже? Тип?

По второму: начально где нахожусь (или где угодно?), сколько выходов может быть (или тоже сколько угодно?)
0
2300 / 1220 / 246
Регистрация: 16.03.2008
Сообщений: 5,822
Записей в блоге: 2
30.07.2011, 19:02 42
Цитата Сообщение от kravam Посмотреть сообщение
И я действительно крут- я знаю вещи. Правда определение им дать не могу, но прерогативу говорить о названиях вещей я оставляю тебе.
Мда..... Считайте, что я опять вам завидую. Минусую.

ЗЫ Вот когда хоть кто то другой скажет на форуме "kravam - крут" - это будет чего то стоить, пока об это говорите только вы - прямой путь к состоянию ламерства.

Можно до умопомрачения говорить что вы написали целый класс для обхода матрицы. Но вы даже не можете толком его протестировать - т.к. мало представляете круг задач в которых это будет помощью. И как всегда не можете адекватно реагировать на критику. Только и делаете, что визжите "Я крут. Я вам счастье принес"
0
Делаю внезапно и красиво
Эксперт С++
1313 / 1228 / 72
Регистрация: 22.03.2011
Сообщений: 3,744
30.07.2011, 19:06 43
Всё, мне надоела таинственность и я написал альтернативу этому классу.
Распространяется без лицензии, код принадлежит всему программирующему сообществу.
Поиск происходит из любой точки во всех направлениях.
Пользователю достаточно задать предикат принадлежности точки пути, предикат определения конечной точки (т.е. завершения поиска) и функцию изменения точки в матрице.
А потом функция Process будет крутиться-вертеться и САМА всё за вас сделает!
Воть.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//предикат принадлежности точки пути
typedef bool (*TestPosition)( const int ** matix, int x, int, y );
// Предикат определения конечной точки
typedef bool (*LastPoint)( const int ** matix, int x, int, y  );
// Изменение точки пути
typedef void (*CorrectPoint)( const int ** matix, int x, int, y );
 
int global_X = 0;
int global_Y = 0;
 
void Process( int ** matrix, TestPosition cbTest, LastPoint cbLast, CorectPoint cbCorrect, int x, int y )
{
      if( global_X <= x || global_Y <= y )
          return;
 
      if( cbLast(matrix, x,y) )
          return;
 
     int dx[4] = {-1,0,0,1};
     int dy[4] = {0,-1,1,0};
     for( int i = 0; i < 4; ++i )
     {
              if( cbTestPoint(matrix, x+dx[i], y+dy[i]) )
              {
                    cbCorrect( matrix, x+dx[i], y_dy[i] );
                    Process(matrix, cbTest, cbLast, cbCorrect, x+dx[i], y+dy[i] );
              }
     }
}
1
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
30.07.2011, 19:10  [ТС] 44
Цитата Сообщение от Evg Посмотреть сообщение
ТОгда не берись за реализацию универсальных вещей, которые предлагаешь людям
Всё бы ничё, но многое из прочитанного мной, именно таково. То есть понятно автору и никому больше. (Я не имею ввиду С\С++, скорее это касается формата PE файлов и прочая)
Что делать?
Вот что делаю я: я просто засучиваю рукава и начинаю вникать вникать и вникать. В бредятину. И ты знаешь, получается... Это тяжело. И я не гоню на авторов. А знаешь, почему? Потом, что сам пишу то, что мне трудно. Хотя формально ты прав: не можешь объяснить- не пиши. А вообще это философский вопрос- что считать приоритетом- знания языка или знания грамматики языка. Я грамотно говорю, но правил не знаю.

(Хотя я уже говорил про двойные стандарты, где-то мы против того, чтобы разжевать и положить в рот, а где-то именно нужно разжевать и положить в рот)

Учился бы в институте- знал бы.
0
Делаю внезапно и красиво
Эксперт С++
1313 / 1228 / 72
Регистрация: 22.03.2011
Сообщений: 3,744
30.07.2011, 19:11 45
Цитата Сообщение от kravam Посмотреть сообщение
А мне нужно чтобы их можно было возвращать в main
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class My
{
public:
     int GetWidth() { return width; }
     int width;
};
 
int main()
{
     My my;
     ...
 
    // Чем не устраивает???
    my.width = 100500;
    int w = my.GetWidth();
}
0
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
30.07.2011, 19:16  [ТС] 46
Цитата Сообщение от Deviaphan Посмотреть сообщение
А потом функция Process будет крутиться-вертеться и САМА всё за вас сделает!
Не сделает.
Хотя бы: в одну и ту же точку нельзя войти дважды. Как ты в предикате будешь осуществлять проверку, был ты в этой точке или нет?

У глупого меня для этого существует вектор пар пройденных пар. И он возвращается функцией методом. Её можно вызывать из предиката и проверять координаты потенциальных точек на принадлежность к такому вектору. Если они там есть- возвращается false, если нет, то bool

А у умного тебя такого нет.
0
Делаю внезапно и красиво
Эксперт С++
1313 / 1228 / 72
Регистрация: 22.03.2011
Сообщений: 3,744
30.07.2011, 19:22 47
Цитата Сообщение от kravam Посмотреть сообщение
А у умного тебя такого нет.
Что значит нет? Там так же создаётся список посещённых координат, в функции CorrectPoint. Просто я этот код под GPL буду поставлять, а остальную часть за бесплатно. Вот бесплатная всем и доступна.

Добавлено через 1 минуту
Цитата Сообщение от kravam Посмотреть сообщение
Хотя бы: в одну и ту же точку нельзя войти дважды.
Кто сказал, что нельзя? Вот Evg привёл задачу, где разрешается многократно проходить по одной и той же точке, но её "стоимость" не учитывается. Мой вариант с этой задачей справится, твой - нет.
И я умный, да.

Добавлено через 1 минуту
Ах да, версию в виде класса и без глобальных переменных готов подарить за 100 денег на мой счёт в швейцарском банке, плиз.
0
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
30.07.2011, 19:26  [ТС] 48
Deviaphan, этот ход
C++
1
2
3
public:
     int GetWidth() { return width; }
     int width;
фуфловый.

Я просил в GetWidth объявить локальную переменную и её же возвратить. Просьба: не компиль больше в уме, а то мой компилятор за тобой не поспевает.

Добавлено через 2 минуты
Deviaphan, я юмор твой оценил, всё на этом.
0
Делаю внезапно и красиво
Эксперт С++
1313 / 1228 / 72
Регистрация: 22.03.2011
Сообщений: 3,744
30.07.2011, 19:27 49
Цитата Сообщение от kravam Посмотреть сообщение
Я просил в GetWidth объявить локальную переменную и её же возвратить.
C++
1
2
3
4
5
6
7
8
9
10
class My2
{
public:
       int GetSome()
       {
              // Так в чём проблема то???
             int  local = 123;
             return local;  
       }
};
0
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
30.07.2011, 19:30  [ТС] 50
Проблема в том, что локальная переменная должна вернуться МЕТОДОМ в main
В общем, избавь меня от необходимости уточнять и без того уточнённую просьбу. До свидания.
0
Делаю внезапно и красиво
Эксперт С++
1313 / 1228 / 72
Регистрация: 22.03.2011
Сообщений: 3,744
30.07.2011, 19:33 51
И снова здравствуй.

Несколькими постами выше я тебе привёл код, как из main передать локальную переменную в класс и как вернуть её из него обратно. Причём сразу двумя различными способами: непосредственно и через метод. Какие такие утончённые вопросы могут у тебя оставаться после столь конкретного ответа?
0
Evg
Эксперт CАвтор FAQ
21279 / 8301 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
30.07.2011, 23:39 52
Цитата Сообщение от kravam Посмотреть сообщение
ОК, это действенный способ окатить меня ледяным душем. Конкретизируй условия не до конечных, но: угол левый верхний или нижний (или любой, то же касается и правого угла)? Ограничение я так понял любое (будет рандомное)... вроде ничё не пропустил. Да, числа рандомные тоже? Тип?
По второму: начально где нахожусь (или где угодно?), сколько выходов может быть (или тоже сколько угодно?)
Принципиальной разницы нет. Я тебе просто привёл пример задач, которые в теории можно решать при помощи матрицы и универсального класса поиска пути. Какая в пень разница какие конкретные цифры и начальные точки?

Цитата Сообщение от kravam Посмотреть сообщение
Вот что делаю я: я просто засучиваю рукава и начинаю вникать вникать и вникать. В бредятину. И ты знаешь, получается...
С учётом того, что твой код строго засекречен, а внятного объяснения, как пользоваться этим интерфейсом нет, то непонятно, во что вообще вникать
0
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
31.07.2011, 00:41  [ТС] 53
Я уже решаю первую задачу. Вникать надо в шаблон тык скыть решения какой я предложил. Кто заинтересуется- тому дам и класс.

Добавлено через 13 минут
И да, кстати. Если ты уж даёшь задание, то позаботься хотя бы о его некоторой корректности
Вот матрица:
1 2
3 4

Начинаем с левого нижнего угла, идём в правый верхний. Сумма пройденых клеток,включая начальную и конечную должна быть не больше 6-ти. А теперь вопрос на засыпку: сколько ты видишь путей?
0
Делаю внезапно и красиво
Эксперт С++
1313 / 1228 / 72
Регистрация: 22.03.2011
Сообщений: 3,744
31.07.2011, 07:31 54
Ах да, там в моём коде ещё одна функция есть, которая генерирует список допустимых перемещений. А то как-то жёстко закодировал, что только в четыре соседних можно. Нехорошо поступил. Теперь можно по любым правилам перемещаться...
0
Evg
Эксперт CАвтор FAQ
21279 / 8301 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
31.07.2011, 10:44 55
Цитата Сообщение от kravam Посмотреть сообщение
Начинаем с левого нижнего угла, идём в правый верхний. Сумма пройденых клеток,включая начальную и конечную должна быть не больше 6-ти. А теперь вопрос на засыпку: сколько ты видишь путей?
Вопросы типа "сколько путей" пользователя не должны заботить, потому как это исключительно забота твоего класса. Потому что нафига пользователю твой класс, если ему самому придётся пути перебирать?
0
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
31.07.2011, 12:26  [ТС] 56
А вы не пользователь. Вы задаёте задачу ученику, чтобы он протестил класс, вы учитель. Я потом скажу: путей столько-то, а вы сверите с ответом. Учитель задаёт задачу (это ваша задача, кстати) и он должен знать ответ. Задача проще некуда. Так каков ответ?

(А за меня решение найдёт мой класс, а вы решение уже должны знать).
0
Evg
Эксперт CАвтор FAQ
21279 / 8301 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
31.07.2011, 12:33 57
Цитата Сообщение от kravam Посмотреть сообщение
Вы задаёте задачу ученику, чтобы он протестил класс, вы учитель
Я не учитель. Ровно так же, как не пионервожатый и не воспитатель. Я тебе обозначил направление, в котором двигаться, но вести тебя за ручку не собираюсь. Если при такой общей постановке вопроса ты не в состоянии самостоятельно поставить сам себе конкретную задачу, то лучше завязывай с программированием
0
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
31.07.2011, 13:06  [ТС] 58
Да я-то в состоянии, я давно уже поставил. А вы не удосужились этого сделать. Причём сделать надо было МИНИМУМ. Но западло, ладно. Ну раз вам западло, то вот: ваша задача имеет бесконечное множество решений. Тут любой класс крякнет. Думать надо прежде чем говорить.
0
Evg
Эксперт CАвтор FAQ
21279 / 8301 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
31.07.2011, 13:14 59
0
Делаю внезапно и красиво
Эксперт С++
1313 / 1228 / 72
Регистрация: 22.03.2011
Сообщений: 3,744
31.07.2011, 13:16 60
Цитата Сообщение от kravam Посмотреть сообщение
Ну раз вам западло, то вот: ваша задача имеет бесконечное множество решений.
Ничего подобного. Задача была чётко ограничена двумя условиями: "стоимостью" пути и максимальным количеством шагов. Соответственно, количество решений конечно.
0
31.07.2011, 13:16
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
31.07.2011, 13:16
Помогаю со студенческими работами здесь

Предлагаю людям как усовершенствовать IDE Dev-Cpp 4.9.9.2
Значит, напомню, среда это давно не развивается уже. Если вы скачаете её, то в предлагаемых пакетах...

Рекурсивный обход. Не могу сделать табуляцию. Обход с выводом имен файлов
Задание простое, ну по крайней мере на первый взгляд. Написать скрипт обхода вложенных директорий с...

Составьте программы для решения следующих задач обработки строк, столбцов и диагоналей матрицы
Задание 2. Составьте программы для решения следующих задач обработки строк, столбцов и диагоналей...

предлагаю программу людям "альтернативное копирование файлов в проводнике"
Суть: программа копирует файл, который передаётся ей параметром командной строки. То есть: в первую...

Решение задач на С++ (написание программы для решения задач)
Добрый день! Помогите с написанием кода для программы, которая будет решать следующие задачки: 1)...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
60
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru