IPB
ЛогинПароль:

> Прочтите прежде чем задавать вопрос!

1. Заголовок темы должен быть информативным. В противном случае тема удаляется ...
2. Все тексты программ должны помещаться в теги [code=pas] ... [/code].
3. Прежде чем задавать вопрос, см. "FAQ", если там не нашли ответа, воспользуйтесь ПОИСКОМ, возможно такую задачу уже решали!
4. Не предлагайте свои решения на других языках, кроме Паскаля (исключение - только с согласия модератора).
5. НЕ используйте форум для личного общения, все что не относится к обсуждению темы - на PM!
6. Одна тема - один вопрос (задача)
7. Проверяйте программы перед тем, как разместить их на форуме!!!
8. Спрашивайте и отвечайте четко и по существу!!!

> Ладьи
nastya_ab
сообщение 16.06.2007 7:11
Сообщение #1


Гость






Помогите пожалуйста!

Ладьи.
Требуется найти такую расстановку 8 ладей на шахматной доске, при которой они не будут угрожать друг другу. Первые три фигуры расставляет пользователь.
 К началу страницы 
+ Ответить 
 
 Ответить  Открыть новую тему 
Ответов(1 - 11)
Lapp
сообщение 16.06.2007 12:19
Сообщение #2


Уникум
*******

Группа: Модераторы
Сообщений: 6 823
Пол: Мужской
Реальное имя: Лопáрь (Андрей)

Репутация: -  159  +


Введи два множества: для букв и для цифр. Затем выбирай расположение так, чтобы ни буква, ни цифра не была в соответствующем множестве (случайный перебор). Найденные позиции добавляй к множествам.
То есть примерно вот так (опускаю тут ручной ввод позиций первых трех ладей) :
  for i:=4 to 8 do begin
repeat l:=Chr(Random(8)+65) until not (l in Letters);
repeat n:=Random(8)+1 until not (n in Numbers);
WriteLn(l,' ',n);
Include(Letters,l);
Include(Numbers,n);
end;


--------------------
я - ветер, я северный холодный ветер
я час расставанья, я год возвращенья домой
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
nasta_ab
сообщение 17.06.2007 19:49
Сообщение #3


Гость






Цитата(Lapp @ 16.06.2007 12:19) *

Введи два множества: для букв и для цифр. Затем выбирай расположение так, чтобы ни буква, ни цифра не была в соответствующем множестве (случайный перебор). Найденные позиции добавляй к множествам.
То есть примерно вот так (опускаю тут ручной ввод позиций первых трех ладей) :
  for i:=4 to 8 do begin
repeat l:=Chr(Random(8)+65) until not (l in Letters);
repeat n:=Random(8)+1 until not (n in Numbers);
WriteLn(l,' ',n);
Include(Letters,l);
Include(Numbers,n);
end;



Спасибо.
 К началу страницы 
+ Ответить 
klem4
сообщение 18.06.2007 6:36
Сообщение #4


Perl. Just code it!
******

Группа: Модераторы
Сообщений: 4 100
Пол: Мужской
Реальное имя: Андрей

Репутация: -  44  +


На сомом деле не лучший вариант, и по идее чисто теоретически возможен вариант когда решение никогда не будет найдено, считай фактически зацикливание, маловероятно конечно но всеже ...

Сообщение отредактировано: klem4 - 18.06.2007 6:36


--------------------
perl -e 'print for (map{chr(hex)}("4861707079204E6577205965617221"=~/(.{2})/g)), "\n";'
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
Michael_Rybak
сообщение 18.06.2007 7:55
Сообщение #5


Michael_Rybak
*****

Группа: Модераторы
Сообщений: 1 046
Пол: Мужской
Реальное имя: Michael_Rybak

Репутация: -  32  +


А по-моему вариант хороший smile.gif Вероятность того, что оно зациклится хотя бы на пять секунд, я думаю, меньше вероятности того, что за эти пять секунд вырубится электричество в комп. классе во время проверки smile.gif А раз просят не какое-то определенное решение, то прикольно, чтоб выдавало рандомное.
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
Lapp
сообщение 19.06.2007 12:21
Сообщение #6


Уникум
*******

Группа: Модераторы
Сообщений: 6 823
Пол: Мужской
Реальное имя: Лопáрь (Андрей)

Репутация: -  159  +


А мне кажется, что klem4 прав. По сути, я ждал этого вопроса. Клем только забыл главный аргумент - масштабируемость. Ведь никто не сказал, что доска не может быть, скажем, 1000х1000 или еще больше.. И тогда эффективность алгоритма резко упадет..

Вот реализация алгоритма, который существенно повышает эффективность при сохранении случайности выбора:
const
b=8; {размер доски}
m=3; {начальное число ладей}

var
l:char;
n,k:byte;
i:integer;
Letters:set of char;
Numbers:set of byte;

begin
Letters:=[];
Numbers:=[];
for i:=1 to m do begin
Write('Введите положение (буква и цифра через пробел) ладьи ',i,': ');
ReadLn(l,n);
Include(Letters,UpCase(l));
Include(Numbers,n);
end;
WriteLn('Остальные ладьи можно расставить так:');
for i:=m+1 to b do begin
k:=Random(b-i+1)+1;
l:='@';
repeat
Inc(l);
while l in Letters do Inc(l);
Dec(k)
until k=0;
Include(Letters,l);
k:=Random(b-i+1)+1;
n:=0;
repeat
Inc(n);
while n in Numbers do Inc(n);
Dec(k)
until k=0;
Include(Numbers,n);
WriteLn(l,' ',n)
end;
ReadLn
end.

Алгоритм, вроде, работает (хотя я уже практически сплю, могут быть ошибки.. smile.gif), но мне почему-то кажется, что он неоптимальный. Кто-нить может быстрее? smile.gif
При существенном увеличении размера доски буквы можно заменить на цифры.


--------------------
я - ветер, я северный холодный ветер
я час расставанья, я год возвращенья домой
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
Michael_Rybak
сообщение 20.06.2007 11:01
Сообщение #7


Michael_Rybak
*****

Группа: Модераторы
Сообщений: 1 046
Пол: Мужской
Реальное имя: Michael_Rybak

Репутация: -  32  +


Во-первых, 1000х1000 не получится из-за set.

А быстрее можно, используя специальную структуру данных, которая позволит находить нужную позицию за логарифмическое время. Т.е. будет n log n

Могу дать ссылку где почитать, если интересно smile.gif
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
Lapp
сообщение 20.06.2007 11:28
Сообщение #8


Уникум
*******

Группа: Модераторы
Сообщений: 6 823
Пол: Мужской
Реальное имя: Лопáрь (Андрей)

Репутация: -  159  +


Цитата(Michael_Rybak @ 20.06.2007 12:01) *

Могу дать ссылку где почитать, если интересно smile.gif

Фи, ссылка...
А мозги на что? smile.gif))

Да, с множествами я лопухнулся, понял наутро smile.gif. 255 - и отвали..
Значит, надо иначе


--------------------
я - ветер, я северный холодный ветер
я час расставанья, я год возвращенья домой
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
volvo
сообщение 20.06.2007 11:35
Сообщение #9


Гость






Цитата
255 - и отвали..
Или реализуй BigSet (почему я и пользуюсь всегда Include/Exclude вместо +/-) и работай хоть до 10000 ...
 К началу страницы 
+ Ответить 
Michael_Rybak
сообщение 20.06.2007 15:09
Сообщение #10


Michael_Rybak
*****

Группа: Модераторы
Сообщений: 1 046
Пол: Мужской
Реальное имя: Michael_Rybak

Репутация: -  32  +


Цитата
Фи, ссылка...


Договорились - давайте придумывать smile.gif
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
Lapp
сообщение 23.06.2007 2:34
Сообщение #11


Уникум
*******

Группа: Модераторы
Сообщений: 6 823
Пол: Мужской
Реальное имя: Лопáрь (Андрей)

Репутация: -  159  +


Цитата(Michael_Rybak @ 20.06.2007 16:09) *

Договорились - давайте придумывать smile.gif

Я некоторое время чувствовал себя некомфортно, как бы с долгом smile.gif. Сегодня нашел минутку подумать над этой задачей. Вот результат.. smile.gif
Я привожу код, который заполняет массив [1..n] неповторяющимися случайными числами от 1 до n. Код не использует множеств, так что размер массива ограничен выбранным типом переменных (в ТР - по сути, размером блока). Код должен работать, мне кажется, быстрее предыдущего моего варианта.
Принцип такой:
- заполняем массив (RestNum) номерами по порядку (это те номера, которые остались);
- в цикле выдергиваем из этого массива по одному элементу случайным образом и кладем в массив Num, заполняя его по порядку;
- образовавщуюся в RestNum от изымания элемента дыру заполняем, сдвигая хвост массива на один элемент влево, начиная с номера сразу за дырой;
- размер RestNum при этом как бы эффективно уменьшается на 1 (переменная m), что мы учитываем, уменьшая диапазон случайных чисел.
Вот сам код. Его можно оформить в виде процедуры при желании smile.gif. Если нужно только выводить номера на печать или в файл, то массив Num по сути не нужен, можно вдвое сэкономить память.
const
n=20;

type
tRange=array[1..n]of integer;

var
Num,RestNum:tRange;
i,j,k,m:integer;

begin
for i:=1 to n do RestNum[i]:=i;
m:=n;
for i:=1 to n do begin
k:=Random(m)+1;
Num[i]:=RestNum[k];
if k<m then Move(RestNum[k+1],RestNum[k],(m-k)*SizeOf(Integer));
Dec(m)
end;
for i:=1 to n do Write(Num[i]:3);
ReadLn
end.


Сообщение отредактировано: Lapp - 23.06.2007 3:50


--------------------
я - ветер, я северный холодный ветер
я час расставанья, я год возвращенья домой
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
Michael_Rybak
сообщение 23.06.2007 13:04
Сообщение #12


Michael_Rybak
*****

Группа: Модераторы
Сообщений: 1 046
Пол: Мужской
Реальное имя: Michael_Rybak

Репутация: -  32  +


Lapp, +1. А я знаете как решил ее относительно недавно? За n log n. Берем группу, идем по ней, и разбиваем на две случайным образом: каждый элемент с равной вероятностью оказывается в первой или второй. Потом рекурсивно перемешиваем подгруппы, и сливаем вместе smile.gif

Кстати, std::random_shuffle в C++ работает именно так, как вы описали.

А что касается специальных структур данных, о которых я говорил - с их помощью можно работать с массивом, сохраняя порядок (не перемещая хвост в дырку).
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 

 Ответить  Открыть новую тему 
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 



- Текстовая версия 20.07.2025 19:14
Хостинг предоставлен компанией "Веб Сервис Центр" при поддержке компании "ДокЛаб"