Переключение на Главную Страницу Страницы: [1]  ОтправитьПечать
Очень популярная тема (более 25 ответов) Разминка для головы. Оптимальный алгоритм. (число прочтений - 8042 )
JohnyDeath
1c++ power user
1c++ donor
Отсутствует



Сообщений: 3050
Местоположение: Волгоград
Зарегистрирован: 19. Мая 2006
Пол: Мужской
Разминка для головы. Оптимальный алгоритм.
21. Мая 2010 :: 11:36
Печать  
Задача с 1С связана чуть менее чем ничего. Но я знаю, что здесь собираются талантливые люди, у которых всегда можно спросить совета. Есть задача по проведению турнира по швейцарской системе проведения турниров.
Не могу найти оптимальный способ поиска "ранее не игравших пар". Поконкретнее:
На входе имеем Список (массив) Людей размером ВсегоЛюдей (всегда четное) в каком либо туре. До этого было какое-то количество туров, где некоторые из этих людей могли играть между собой. Задача: разбить этот массив на пары так, чтобы ни одна из пар не играла ранее.
Например, имеем 6 человек {1,2,3,4,5,6}. В первом туре были проведены встречи:
1-2, 3-4, 5-6
Во втором:
1-4,2-5,3-6
Над составить пары на Третий тур, причем уже сыгравшие комбинации надо исключить.

Есть идеи? У меня одни тупые переборы в голове мелькают.
  
Наверх
 
IP записан
 
JohnyDeath
1c++ power user
1c++ donor
Отсутствует



Сообщений: 3050
Местоположение: Волгоград
Зарегистрирован: 19. Мая 2006
Пол: Мужской
Re: Разминка для головы. Оптимальный алгоритм.
Ответ #1 - 21. Мая 2010 :: 11:43
Печать  
В БД есть 2 таблички:
1) "Люди" с колонками: "НомерЧеловека" (уникальный), "ФИО"
2) "Пары" с колонками:
-"ИдПары",
-"ИдИгрока1",
-"ИдИгрока2",
-"КолИгр" - кол. игр, сыгранных между этими игроками во всех турах

В Этой табличке я предполагаю, что ИдПары будет одинаковым для комбинаций "ИдИгрока1"-"ИдИгрока2", "ИдИгрока2"-"ИдИгрока1". Т.е. для  3-х участников будет такая:
ИдПары - ИдИгрока1 - ИдИгрока2
1 - 1 - 2
2 - 1 - 3
3 - 2 - 3
1 - 2 - 1
3 - 3 - 2
2 - 3 - 1

Структуру БД можно менять, она пока только у меня в голове на листочке
  
Наверх
 
IP записан
 
berezdetsky
1c++ power user
Отсутствует


barba non facit sisadminum

Сообщений: 1986
Местоположение: Москва
Зарегистрирован: 19. Мая 2006
Пол: Мужской
Re: Разминка для головы. Оптимальный алгоритм.
Ответ #2 - 21. Мая 2010 :: 11:51
Печать  
В одном туре один человек участвует 1 раз?
  

пароль как коньяк, чем больше звездочек, тем лучше
Наверх
IP записан
 
chessman
God Member
*****
Отсутствует



Сообщений: 1084
Зарегистрирован: 10. Августа 2007
Re: Разминка для головы. Оптимальный алгоритм.
Ответ #3 - 21. Мая 2010 :: 12:22
Печать  
Как вариант : представить в виде чисел
1-2 ~ 12 = 21 (выкидываем)
3-4 ~ 34 = 43 (выкидываем)
5-6 ~ 56 = 65 (выкидываем)

Бежим от 11 до 66. Повторы тоже выкидываем.



  
Наверх
 
IP записан
 
JohnyDeath
1c++ power user
1c++ donor
Отсутствует



Сообщений: 3050
Местоположение: Волгоград
Зарегистрирован: 19. Мая 2006
Пол: Мужской
Re: Разминка для головы. Оптимальный алгоритм.
Ответ #4 - 21. Мая 2010 :: 12:50
Печать  
berezdetsky писал(а) 21. Мая 2010 :: 11:51:
В одном туре один человек участвует 1 раз?

Да
  
Наверх
 
IP записан
 
JohnyDeath
1c++ power user
1c++ donor
Отсутствует



Сообщений: 3050
Местоположение: Волгоград
Зарегистрирован: 19. Мая 2006
Пол: Мужской
Re: Разминка для головы. Оптимальный алгоритм.
Ответ #5 - 21. Мая 2010 :: 13:03
Печать  
chessman писал(а) 21. Мая 2010 :: 12:22:
Как вариант : представить в виде чисел
1-2 ~ 12 = 21 (выкидываем)
3-4 ~ 34 = 43 (выкидываем)
5-6 ~ 56 = 65 (выкидываем)

Бежим от 11 до 66. Повторы тоже выкидываем.

Не совсем понял тебя. Для одной пары такой вариант подойдет, не спорю. Но нужно ж всех расставить.
Да и склеивать их необязательно, если у меня есть табличка "Пары". Там достаточно сделать запрос типа такого (определяются все возможные пары для игрока "Игрок_1"):
Код
Выбрать все
SELECT
FROM Пары
WHERE Пары.Игрок1 = "Игрок_1"
  AND Пары.КолИгр = 0
  AND Пары.Игрок2 IN (СпискоИгроковВ_ТекущемТуре)
GROUP BY Пары.ИдПары 


  
Наверх
 
IP записан
 
berezdetsky
1c++ power user
Отсутствует


barba non facit sisadminum

Сообщений: 1986
Местоположение: Москва
Зарегистрирован: 19. Мая 2006
Пол: Мужской
Re: Разминка для головы. Оптимальный алгоритм.
Ответ #6 - 21. Мая 2010 :: 13:04
Печать  
JohnyDeath писал(а) 21. Мая 2010 :: 12:50:
berezdetsky писал(а) 21. Мая 2010 :: 11:51:
В одном туре один человек участвует 1 раз?

Да

Тогда в один проход задача не решается, нужен какой-то оптимизирующий алгоритм.
Т.е., к примеру, 1-6, 2-3, 4-5 - допустимое решение, а 1-3, 2-4, ?-? - нет.

Рекомендую Microsoft Solver Foundation.  Улыбка

Ну или перебор, если данных не слишком много..

Да, просто список доступных пар можно получить так:
Код
Выбрать все
declare @люди table (id integer)

insert into @люди values (1)
insert into @люди values (2)
insert into @люди values (3)
insert into @люди values (4)
insert into @люди values (5)
insert into @люди values (6)

declare @турниры table (id integer, чел1 integer, чел2 integer)

insert into @турниры values (1, 1, 2)
insert into @турниры values (1, 3, 4)
insert into @турниры values (1, 5, 6)
insert into @турниры values (2, 1, 4)
insert into @турниры values (2, 2, 5)
insert into @турниры values (2, 3, 6)

select люди1.id чел1, люди2.id чел2
from @люди люди1
	inner join @люди люди2 on люди1.id < люди2.id
where not люди2.id in (
		select чел2
		from @турниры
		where чел1 = люди1.id
	) 

  

пароль как коньяк, чем больше звездочек, тем лучше
Наверх
IP записан
 
JohnyDeath
1c++ power user
1c++ donor
Отсутствует



Сообщений: 3050
Местоположение: Волгоград
Зарегистрирован: 19. Мая 2006
Пол: Мужской
Re: Разминка для головы. Оптимальный алгоритм.
Ответ #7 - 21. Мая 2010 :: 13:06
Печать  
JohnyDeath писал(а) 21. Мая 2010 :: 12:50:
berezdetsky писал(а) 21. Мая 2010 :: 11:51:
В одном туре один человек участвует 1 раз?

Да

Только в каждом туре все участники разбиваются на группы. Т.е. Один человек в каждом новом туре может попасть в группу с людьми, которыми вообще никогда не играл, либо играл с некоторыми из них.
  
Наверх
 
IP записан
 
alexdd
Senior Member
****
Отсутствует


I Love YaBB 2!

Сообщений: 347
Зарегистрирован: 25. Июня 2007
Re: Разминка для головы. Оптимальный алгоритм.
Ответ #8 - 21. Мая 2010 :: 13:14
Печать  
вот наваял вариантикУлыбка у меня получается 21 игра для 6 игроков. Не знаю насколько правильно.
Исходные данные:
Код
Выбрать все
create table #players (id int primary key,name varchar(50))
create table #games(id int identity primary key,player1 int,player2 int)


insert into #players values(1,'Иванов')
insert into #players values(2,'Петров')
insert into #players values(3,'Сидоров')
insert into #players values(4,'Пупкин')
insert into #players values(5,'Ступкин')
insert into #players values(6,'Рабинович')
 



Поиск пары:
Код
Выбрать все
declare @p1 int,@p2 int

select top 1
 @p1 = vt.p1,@p2 = vt.p2
from(
select distinct
 case when p.id > p2.id then p.id else p2.id end p1,
 case when p.id < p2.id then p.id else p2.id end p2
from #players p cross join #players p2) vt
left join
 #games g on g.player1 = vt.p1 and g.player2 = vt.p2 or g.player2 = vt.p1 and g.player1 = vt.p2
where
 g.id is null

if @p1 is null
	print 'Вариантов больше нет'
else
	insert into #games values(@p1,@p2)
 

  
Наверх
 
IP записан
 
berezdetsky
1c++ power user
Отсутствует


barba non facit sisadminum

Сообщений: 1986
Местоположение: Москва
Зарегистрирован: 19. Мая 2006
Пол: Мужской
Re: Разминка для головы. Оптимальный алгоритм.
Ответ #9 - 21. Мая 2010 :: 13:20
Печать  
alexdd писал(а) 21. Мая 2010 :: 13:14:
вот наваял вариантикУлыбка у меня получается 21 игра для 6 игроков.

15 должно быть. В твоём варианте игроки играют сами с собой.  Ужас
  

пароль как коньяк, чем больше звездочек, тем лучше
Наверх
IP записан
 
JohnyDeath
1c++ power user
1c++ donor
Отсутствует



Сообщений: 3050
Местоположение: Волгоград
Зарегистрирован: 19. Мая 2006
Пол: Мужской
Re: Разминка для головы. Оптимальный алгоритм.
Ответ #10 - 21. Мая 2010 :: 13:25
Печать  
berezdetsky писал(а) 21. Мая 2010 :: 13:04:
Рекомендую Microsoft Solver Foundation.  Улыбка

Даже примерно не знаю что это такое  Смущённый Даже если это и отличное решение, то что-то мне подсказывает, что я времени убью больше, чем надо

berezdetsky писал(а) 21. Мая 2010 :: 13:04:
Ну или перебор, если данных не слишком много..

Вот какой перебор ты бы сделал. Ведь тут надо в случае "неудачи" возвращаться на несколько шагов назад, т.е. если мы подобрали 3 пары из 4-х, а 4-я пара уже играла между собой, то надо возвращаться назад и переставлять что-то, чтобы получился новый набор, ну и запомнить, какие наборы мы уже просмотрели...
{я понятно изъясняюсь? а то у меня всё как-то параллельно навалилось и в голове каша, поэтому не судите строго}
  
Наверх
 
IP записан
 
alexdd
Senior Member
****
Отсутствует


I Love YaBB 2!

Сообщений: 347
Зарегистрирован: 25. Июня 2007
Re: Разминка для головы. Оптимальный алгоритм.
Ответ #11 - 21. Мая 2010 :: 13:27
Печать  
berezdetsky писал(а) 21. Мая 2010 :: 13:20:
alexdd писал(а) 21. Мая 2010 :: 13:14:
вот наваял вариантикУлыбка у меня получается 21 игра для 6 игроков.

15 должно быть. В твоём варианте игроки играют сами с собой.  Ужас

а блин, ну тогда такУлыбка
Код
Выбрать все
declare @p1 int,@p2 int

select top 1
 @p1 = vt.p1,@p2 = vt.p2
from(
select distinct
 case when p.id > p2.id then p.id else p2.id end p1,
 case when p.id < p2.id then p.id else p2.id end p2
from #players p cross join #players p2) vt
left join
 #games g on g.player1 = vt.p1 and g.player2 = vt.p2 or g.player2 = vt.p1 and g.player1 = vt.p2
where
 g.id is null and vt.p1 <> vt.p2

if @p1 is null
	print 'Вариантов больше нет'
else
	insert into #games values(@p1,@p2)
 

  
Наверх
 
IP записан
 
berezdetsky
1c++ power user
Отсутствует


barba non facit sisadminum

Сообщений: 1986
Местоположение: Москва
Зарегистрирован: 19. Мая 2006
Пол: Мужской
Re: Разминка для головы. Оптимальный алгоритм.
Ответ #12 - 21. Мая 2010 :: 13:38
Печать  
JohnyDeath писал(а) 21. Мая 2010 :: 13:25:
Вот какой перебор ты бы сделал.

Четыре перебора, последовательно:
  • получить все возможные пары;
  • получить все возможные турниры;
  • получить все наборы непересекающихся турниров;
  • найти самый длинный набор турниров.

Как-то так..
  

пароль как коньяк, чем больше звездочек, тем лучше
Наверх
IP записан
 
JohnyDeath
1c++ power user
1c++ donor
Отсутствует



Сообщений: 3050
Местоположение: Волгоград
Зарегистрирован: 19. Мая 2006
Пол: Мужской
Re: Разминка для головы. Оптимальный алгоритм.
Ответ #13 - 21. Мая 2010 :: 14:20
Печать  
alexdd писал(а) 21. Мая 2010 :: 13:27:
berezdetsky писал(а) 21. Мая 2010 :: 13:20:
alexdd писал(а) 21. Мая 2010 :: 13:14:
вот наваял вариантикУлыбка у меня получается 21 игра для 6 игроков.

15 должно быть. В твоём варианте игроки играют сами с собой.  Ужас

а блин, ну тогда такУлыбка

Я, наверное, всё-таки плохо объяснил (или всех не понимаю).
Таблица "Пары" заполняется сразу как только заполнена табличка "Игроки" и кол-во записей в ней будет = n!, где n - количество записей в таблице "Игроки". После того как пара сыграла, то значение в колонке "КолИгр" таблицы "Пары" увеличивается на единицу. Выбрать потом все возможные пары, которые еще не играли из списка текущей подгруппы - не проблема:
Код
Выбрать все
SELECT Пары.Игрок1, Пары.Игрок.2
FROM Пары
WHERE Пары.Игрок1 IN (СпискоИгроковВ_ТекущейПодгруппе)
  AND Пары.Игрок2 IN (СпискоИгроковВ_ТекущейПодгруппе)
  AND Пары.КолИгр = 0
GROUP BY Пары.ИдПары  


Но мы получим примерно такие данные:
  • 1 - 3
  • 1 - 4
  • 1 - 6
  • 2 - 3
  • 2 - 6
  • 2 - 5
  • 2 - 4
  • 3 - 6
  • 4 - 6

Как по-простому из этих данных выдрать только
1 - 3 , 2 - 5 , 4 - 6
?(или какой-либо другой подходящий) Здесь ведь видно, что с 5-м игроком может сыграть ТОЛЬКО 2-й.
  
Наверх
 
IP записан
 
Anatol
Senior Member
****
Отсутствует


тыц, пыц, тыц!!!

Сообщений: 412
Зарегистрирован: 24. Апреля 2009
Re: Разминка для головы. Оптимальный алгоритм.
Ответ #14 - 21. Мая 2010 :: 14:21
Печать  
JohnyDeath писал(а) 21. Мая 2010 :: 11:43:
В БД есть 2 таблички:
1) "Люди" с колонками: "НомерЧеловека" (уникальный), "ФИО"
2) "Пары" с колонками:
-"ИдПары",
-"ИдИгрока1",
-"ИдИгрока2",
-"КолИгр" - кол. игр, сыгранных между этими игроками во всех турах

В Этой табличке я предполагаю, что ИдПары будет одинаковым для комбинаций "ИдИгрока1"-"ИдИгрока2", "ИдИгрока2"-"ИдИгрока1". Т.е. для  3-х участников будет такая:
ИдПары - ИдИгрока1 - ИдИгрока2
1 - 1 - 2
2 - 1 - 3
3 - 2 - 3
1 - 2 - 1
3 - 3 - 2
2 - 3 - 1

Структуру БД можно менять, она пока только у меня в голове на листочке



ид пары это 2 в степени ид игрока

1 = 2
2 = 4
3 = 8
4 = 16
5 = 32
6 = 64

складываем пары между собой получем = ид пары
ид пары не должен быть равен ид игрока (что бы игрок не играл сам с собой  Улыбка )
  
Наверх
wwwICQ  
IP записан
 
JohnyDeath
1c++ power user
1c++ donor
Отсутствует



Сообщений: 3050
Местоположение: Волгоград
Зарегистрирован: 19. Мая 2006
Пол: Мужской
Re: Разминка для головы. Оптимальный алгоритм.
Ответ #15 - 21. Мая 2010 :: 14:29
Печать  
Anatol писал(а) 21. Мая 2010 :: 14:21:
ид пары это 2 в степени ид игрока

1 = 2
2 = 4
3 = 8
4 = 16
5 = 32
6 = 64

складываем пары между собой получем = ид пары
ид пары не должен быть равен ид игрока (что бы игрок не играл сам с собой  Улыбка )

Я ж говорю, заполнить эту таблицу - не есть проблема. Эту таблицу я придумал, чтоб легче выдирать пары, которые не играли для любого выбранного игрока.
  
Наверх
 
IP записан
 
berezdetsky
1c++ power user
Отсутствует


barba non facit sisadminum

Сообщений: 1986
Местоположение: Москва
Зарегистрирован: 19. Мая 2006
Пол: Мужской
Re: Разминка для головы. Оптимальный алгоритм.
Ответ #16 - 21. Мая 2010 :: 14:39
Печать  
JohnyDeath писал(а) 21. Мая 2010 :: 14:20:
Таблица "Пары" заполняется сразу как только заполнена табличка "Игроки" и кол-во записей в ней будет = n!, где n - количество записей в таблице "Игроки".

Занятная комбинаторика.  Смех

Может того.. утро вечера мудренее?
  

пароль как коньяк, чем больше звездочек, тем лучше
Наверх
IP записан
 
JohnyDeath
1c++ power user
1c++ donor
Отсутствует



Сообщений: 3050
Местоположение: Волгоград
Зарегистрирован: 19. Мая 2006
Пол: Мужской
Re: Разминка для головы. Оптимальный алгоритм.
Ответ #17 - 21. Мая 2010 :: 14:50
Печать  
Иван, а разве не так? Насколько я помню, факториал числа  n - это количество перестановок n элементов.
Если ты про то, что пара 1-2 эквивалентна паре 2-1 - да, так и есть, но я намеренно заполнял таблицу "Пары" всеми возможными комбинациями чтобы в запросах писать условие:
Код
Выбрать все
WHERE Пары.Игрок1 = "Игрок_1" 


иначе пришлось бы писать так:
Код
Выбрать все
WHERE Пары.Игрок1 = "Игрок_1" OR Пары.Игрок2 = "Игрок_1" 


со всеми вытекающими...

berezdetsky писал(а) 21. Мая 2010 :: 14:39:
Может того.. утро вечера мудренее?  

Ну да, наверное. Если будут какие-нибудь идеи - напиши обязательно. Я чё-т уже и сплю плохо  Улыбка
Сейчас меня тянет в сторону алгоритмов с "деревьями", хотя я с ними вообще никогда не работал  Нерешительный
  
Наверх
 
IP записан
 
berezdetsky
1c++ power user
Отсутствует


barba non facit sisadminum

Сообщений: 1986
Местоположение: Москва
Зарегистрирован: 19. Мая 2006
Пол: Мужской
Re: Разминка для головы. Оптимальный алгоритм.
Ответ #18 - 21. Мая 2010 :: 16:02
Печать  
JohnyDeath писал(а) 21. Мая 2010 :: 14:50:
Иван, а разве не так? Насколько я помню, факториал числа  n - это количество перестановок n элементов.

Это для множеств с повторениями. Без повторений количество перестановок равно n! / (k! * (n - k)!). Для пар (k = 2) это будет n * (n - 1) / 2.


JohnyDeath писал(а) 21. Мая 2010 :: 14:50:
иначе пришлось бы писать так:

Ну.. Мне же в #6 не пришлось..  Улыбка
  

пароль как коньяк, чем больше звездочек, тем лучше
Наверх
IP записан
 
Anatol
Senior Member
****
Отсутствует


тыц, пыц, тыц!!!

Сообщений: 412
Зарегистрирован: 24. Апреля 2009
Re: Разминка для головы. Оптимальный алгоритм.
Ответ #19 - 21. Мая 2010 :: 16:50
Печать  
Помоему задача поставлена не совсем корректно.
по Швейцарской системе распределение пар еще зависит от результат предыдущего тура, выигравшие играют с выигрывавшими, а проигравшие с проигравшими.

#13 на верно следует перечитать правила, а то ерунда получается
  
Наверх
wwwICQ  
IP записан
 
JohnyDeath
1c++ power user
1c++ donor
Отсутствует



Сообщений: 3050
Местоположение: Волгоград
Зарегистрирован: 19. Мая 2006
Пол: Мужской
Re: Разминка для головы. Оптимальный алгоритм.
Ответ #20 - 22. Мая 2010 :: 07:18
Печать  
berezdetsky писал(а) 21. Мая 2010 :: 16:02:
JohnyDeath писал(а) 21. Мая 2010 :: 14:50:
Иван, а разве не так? Насколько я помню, факториал числа  n - это количество перестановок n элементов.

Это для множеств с повторениями. Без повторений количество перестановок равно n! / (k! * (n - k)!). Для пар (k = 2) это будет n * (n - 1) / 2.

Это я понимаю. Но мне кажется, что в данном случае избыточность этой таблицы полезна.
При виде всех этих восклицательных знаков вспомнились фразы типа: "цэ из эн по ка"; и школьный сборник задач по математике "Сканави". Институт, почему-то, вообще не вспомнился...

berezdetsky писал(а) 21. Мая 2010 :: 16:02:
JohnyDeath писал(а) 21. Мая 2010 :: 14:50:
иначе пришлось бы писать так:

Ну.. Мне же в #6 не пришлось..  Улыбка

Да я и не спорю, что можно найти тысячу и один способ построения запроса и этой таблицы. Но вопрос-то сейчас в другом:
Как из пар, которые могут играть в этом туре с заданным набором участников, выбрать ту комбинацию, которая бы покрывала всех заданных участников. Получить сам список доступных пар для данных участников мы уже поняли и написали несколько запросов.
  
Наверх
 
IP записан
 
JohnyDeath
1c++ power user
1c++ donor
Отсутствует



Сообщений: 3050
Местоположение: Волгоград
Зарегистрирован: 19. Мая 2006
Пол: Мужской
Re: Разминка для головы. Оптимальный алгоритм.
Ответ #21 - 22. Мая 2010 :: 07:45
Печать  
Anatol писал(а) 21. Мая 2010 :: 16:50:
Помоему задача поставлена не совсем корректно.
по Швейцарской системе распределение пар еще зависит от результат предыдущего тура, выигравшие играют с выигрывавшими, а проигравшие с проигравшими.

#13 на верно следует перечитать правила, а то ерунда получается

Давай на примере покажу.
Всего в чемпионате участвуют 6 человек: 1,2,3,4,5,6. В первом туре они разбиваются на пары согласно жребию (т.к. кол-во очков у всех = 0 и рейтинга ни у кого никакого нет) на вот такие пары:
Игрок1 Игрок2 Победитель
1 2 1
3 4 3
5 6 5

Во втором туре, согласно правилам, игроки разбиваются на подгруппы по количеству набранных очков. Мы имеем две подгруппы: 1,3,5 (Победители) и 2,4,6 (Проигравшие). Т.к. первая подгруппа имеет нечетное кол-во участников, то последнего выкидываем в ближайшую очковую группу. Тогда имеем такие подгруппы: {1,3} и {5,2,4,6}. Играем:
Игрок1 Игрок2 Победитель
1 3 3
5 2 2
4 6 4

Теперь перед 3-м туром имеем:
1. Игрок 3 имеет 2 очка
2. Игроки 1,2,4,5 имеют по одному очку
3. Игрок 6 имеет 0 очков
Разбиваемся на подгруппы (согласно очкам и правилу "четности"): {3,1,2,4}, {5,6}
Т.о. в 3-м туре имеем первую подгруппу, где некоторые игрокуи уже играли между собой. А именно:
Пара: 3 - 4
и Пара: 1 - 2


Как раз и надо составить тур для первой подгруппы, где на входе имеем доступные пары:
2-3
1-4
2-4
и список игроков: {1,2,3,4}
« Последняя редакция: 22. Мая 2010 :: 16:09 - JohnyDeath »  
Наверх
 
IP записан
 
berezdetsky
1c++ power user
Отсутствует


barba non facit sisadminum

Сообщений: 1986
Местоположение: Москва
Зарегистрирован: 19. Мая 2006
Пол: Мужской
Re: Разминка для головы. Оптимальный алгоритм.
Ответ #22 - 22. Мая 2010 :: 12:18
Печать  
На сколько я понял, жеребьёвка используется только в первом туре. В последующих - по рейтинговому принципу. Следствие: Цитата:
Если строго придерживаться всех правил распределения по парам, то практически все пары складываются однозначно, то есть почти не бывает свободы выбора.

На твоём примере, с учётом коэффициента Бухгольца, последовательность в группе = {4, 2, 1, 3}, а значит пары - 4-1 и 2-3.

Можно, конечно, решить и простым перебором из двух вложенных циклов..
  

пароль как коньяк, чем больше звездочек, тем лучше
Наверх
IP записан
 
JohnyDeath
1c++ power user
1c++ donor
Отсутствует



Сообщений: 3050
Местоположение: Волгоград
Зарегистрирован: 19. Мая 2006
Пол: Мужской
Re: Разминка для головы. Оптимальный алгоритм.
Ответ #23 - 22. Мая 2010 :: 15:21
Печать  
Иван, а вот ты бы поверил без оглядки высказыванию о том, что "практически все пары складываются однозначно"? Я не поверил, что всё может обойтись, а смоделировать все возможные комбинации, которые могут произойти в игре с 500 участниками я не в силах, поэтому и стал искать запасное решение.
Коэф-т Бухгольца конечно же учитывается при формировании групп. Этот пример я дал только для того, чтобы показать, что некоторые игроки могут попадать в одну группу несколько раз. Привести пример, где правило формирование групп и пар не сработало, не могу, ибо очень трудно придумать такую ситуацию. Но, как обычно и бывает, уже в боевых условиях такая ситуация запрсто может вылезти при первом же применении, а там уже ручками сами пользователи этой программы вряд ли смогут что-то сделать (читай "пестец турниру")

Общий алгоритм примерно такой:
1. Играем (вносим данные о сыгранных матчах)
2. Сортируем всех по (КоличествоОчков, Коэф. Бухгольца)
3. Разбиваем на подгруппы в зависимости от кол-ва очков
4. Разбиваемся на пары для игры. А именно:
  а)Пробуем классическим методом (первый из первой половины группы играет с первым из второй половины).
  б)Если он не срабатывает применяем обсуждаемый здесь алгоритм.
  в)Если и он не срабатывает, откатываемся на вариант (а) и забиваем на то, что некоторые играют друг с другом уже не впервый раз. Сыграют и еще разок.

и так для каждого тура.

И да, я тоже остановился на алгоритме с 2-мя вложенными циклами, но почему-то душа у меня к нему не лежит, кажется будто он делает что-то не так (доказать не могу  Нерешительный).
  
Наверх
 
IP записан
 
JohnyDeath
1c++ power user
1c++ donor
Отсутствует



Сообщений: 3050
Местоположение: Волгоград
Зарегистрирован: 19. Мая 2006
Пол: Мужской
Re: Разминка для головы. Оптимальный алгоритм.
Ответ #24 - 22. Мая 2010 :: 15:56
Печать  
berezdetsky писал(а) 22. Мая 2010 :: 12:18:
На твоём примере, с учётом коэффициента Бухгольца, последовательность в группе = {4, 2, 1, 3}, а значит пары - 4-1 и 2-3.

Коэф. Бухгольца для этих игроков:
у 1го - 2 балла
у 2го - 2 балла
у 3го - 1 балл
у 4го - 1 балл
(а как у тебя получилось так однозначно расставить?)

Т.о. можем получить 4 варианта расстановки группы: {1,2,3,4}, {1,2,4,3}, {2,1,3,4}, {2,1,4,3}
Первый вариант не подходит, т.к. 1-й с 3-м уже играли.
  
Наверх
 
IP записан
 
berezdetsky
1c++ power user
Отсутствует


barba non facit sisadminum

Сообщений: 1986
Местоположение: Москва
Зарегистрирован: 19. Мая 2006
Пол: Мужской
Re: Разминка для головы. Оптимальный алгоритм.
Ответ #25 - 22. Мая 2010 :: 16:27
Печать  
JohnyDeath писал(а) 22. Мая 2010 :: 15:21:
Иван, а вот ты бы поверил без оглядки высказыванию о том, что "практически все пары складываются однозначно"?

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

JohnyDeath писал(а) 22. Мая 2010 :: 15:21:
И да, я тоже остановился на алгоритме с 2-мя вложенными циклами, но почему-то душа у меня к нему не лежит, кажется будто он делает что-то не так (доказать не могу  Нерешительный).

Возможно, мы имеем ввиду разные алгоритмы. Я говорю о стандартном алгоритме генерации k-элементных подмножеств из комбинаторики.
  

пароль как коньяк, чем больше звездочек, тем лучше
Наверх
IP записан
 
berezdetsky
1c++ power user
Отсутствует


barba non facit sisadminum

Сообщений: 1986
Местоположение: Москва
Зарегистрирован: 19. Мая 2006
Пол: Мужской
Re: Разминка для головы. Оптимальный алгоритм.
Ответ #26 - 22. Мая 2010 :: 16:51
Печать  
JohnyDeath писал(а) 22. Мая 2010 :: 15:56:
berezdetsky писал(а) 22. Мая 2010 :: 12:18:
На твоём примере, с учётом коэффициента Бухгольца, последовательность в группе = {4, 2, 1, 3}, а значит пары - 4-1 и 2-3.

Коэф. Бухгольца для этих игроков:
у 1го - 2 балла
у 2го - 2 балла
у 3го - 1 балл
у 4го - 1 балл
(а как у тебя получилось так однозначно расставить?)

Ээ.. Где-то ошибся.  Смущённый Сейчас пересчитал, получилось
1 - 3 балла, 2 и 4 - по 2 балла, 3 - вне конкуренции, т.к. у него изначально 2 очка против 1 у остальных. Для 2 и 4 применяем усечённый коэффициент Бухгольца, получаем 2 - 1 балл, 4 - 2 балла.
Итого: {2, 4, 1, 3}. Пары - 2-1 и 4-3. Облом.  Ужас

Хотя усечённый коэффициент Бухгольца выглядит несколько сомнительно - я предпочёл бы там не отнимать, а прибавлять..
  

пароль как коньяк, чем больше звездочек, тем лучше
Наверх
IP записан
 
JohnyDeath
1c++ power user
1c++ donor
Отсутствует



Сообщений: 3050
Местоположение: Волгоград
Зарегистрирован: 19. Мая 2006
Пол: Мужской
Re: Разминка для головы. Оптимальный алгоритм.
Ответ #27 - 22. Мая 2010 :: 17:19
Печать  
berezdetsky писал(а) 22. Мая 2010 :: 16:27:
JohnyDeath писал(а) 22. Мая 2010 :: 15:21:
Иван, а вот ты бы поверил без оглядки высказыванию о том, что "практически все пары складываются однозначно"?

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

Даже при кол-ве игроков = 4 мы смоделировали ситуацию, где этот алгоритм обламывается. Вариант "Сыграют и еще разок" мне кажется лучше вариантов: "остановить весь турнир" или "присвоит этим игрокам автоматом какое-то кол-во очков"

berezdetsky писал(а) 22. Мая 2010 :: 16:27:
Возможно, мы имеем ввиду разные алгоритмы. Я говорю о стандартном алгоритме генерации k-элементных подмножеств из комбинаторики.


У меня примерно такой:
Код
Выбрать все
Функция ПолучитьПарыДляИгр(спИгроковГруппы//:СписокЗначений
	,спВозможныхПар//:СписокЗначений
	)

	спНераспределенныхИгроков = СоздатьОбъект("СписокЗначений");
	спИгроковГруппы.Выгрузить(спНераспределенныхИгроков);

	Для й=1 По спВозможныхПар.РазмерСписка() Цикл
		Результат  = СоздатьОбъект("СписокЗначений");
		текПара = спВозможныхПар.ПолучитьЗначение(й);
		Результат.ДобавитьЗначение(текПара);
		ПолучитьИгроковПары(текПара, Игрок1, Игрок2);
		УдалитьИзСписка(спНераспределенныхИгроков, Игрок1, Игрок2);
		Если спНераспределенныхИгроков.РазмерСписка()=0 Тогда
			Возврат Результат;
		КонецЕсли;

		Для ж=1 По спВозможныхПар.РазмерСписка() Цикл
			текПара_2 = спВозможныхПар.ПолучитьЗначение(ж);
			Если текПара=текПара_2 Тогда Продолжить;		КонецЕсли;

			Результат.ДобавитьЗначение(текПара_2);
			ПолучитьИгроковПары(текПара_2, Игрок1, Игрок2);
			УдалитьИзСписка(спНераспределенныхИгроков, Игрок1, Игрок2);
			Если спНераспределенныхИгроков.РазмерСписка()=0 Тогда
				Возврат Результат;
			КонецЕсли;

		КонецЦикла;
	КонецЦикла;

	Возврат "Решений нет!";
КонецФункции	// ПолучитьПарыДляИгр 


Это он же?  Улыбка
  
Наверх
 
IP записан
 
berezdetsky
1c++ power user
Отсутствует


barba non facit sisadminum

Сообщений: 1986
Местоположение: Москва
Зарегистрирован: 19. Мая 2006
Пол: Мужской
Re: Разминка для головы. Оптимальный алгоритм.
Ответ #28 - 22. Мая 2010 :: 17:43
Печать  
JohnyDeath писал(а) 22. Мая 2010 :: 17:19:
Даже при кол-ве игроков = 4 мы смоделировали ситуацию, где этот алгоритм обламывается.

Нет. Мы получили ситуацию, которая решается перестановками. А вот что делать с ситуациями, которые таким образом не решаются - в википедии не написано. Там понадобится какой-то алгоритм перераспределения групп.

JohnyDeath писал(а) 22. Мая 2010 :: 17:19:
Это он же?  Улыбка

А это вообще работает? Если Результат пересоздаётся в цикле, а спНераспределенныхИгроков - нет?
  

пароль как коньяк, чем больше звездочек, тем лучше
Наверх
IP записан
 
JohnyDeath
1c++ power user
1c++ donor
Отсутствует



Сообщений: 3050
Местоположение: Волгоград
Зарегистрирован: 19. Мая 2006
Пол: Мужской
Re: Разминка для головы. Оптимальный алгоритм.
Ответ #29 - 22. Мая 2010 :: 17:52
Печать  
А, ну да. Строчки
Код
Выбрать все
спНераспределенныхИгроков = СоздатьОбъект("СписокЗначений");
спИгроковГруппы.Выгрузить(спНераспределенныхИгроков); 


надо тоже засунуть в цикл.

Работает или нет - не знаю, пока это всё только в голове и на листочках.
Думаешь, что не прокатит? (хотя я тоже в нем сомневаюсь  Улыбка )
  
Наверх
 
IP записан
 
JohnyDeath
1c++ power user
1c++ donor
Отсутствует



Сообщений: 3050
Местоположение: Волгоград
Зарегистрирован: 19. Мая 2006
Пол: Мужской
Re: Разминка для головы. Оптимальный алгоритм.
Ответ #30 - 22. Мая 2010 :: 17:58
Печать  
И еще одну проверочку забыл вставить:
Код
Выбрать все
Функция ПолучитьПарыДляИгр(спИгроковГруппы//:СписокЗначений
	,спВозможныхПар//:СписокЗначений
	)


	Для й=1 По спВозможныхПар.РазмерСписка() Цикл
		спНераспределенныхИгроков = СоздатьОбъект("СписокЗначений");
		спИгроковГруппы.Выгрузить(спНераспределенныхИгроков);
		Результат  = СоздатьОбъект("СписокЗначений");
		текПара = спВозможныхПар.ПолучитьЗначение(й);

		ПолучитьИгроковПары(текПара, Игрок1, Игрок2);
		Результат.ДобавитьЗначение(текПара);

		УдалитьИзСписка(спНераспределенныхИгроков, Игрок1, Игрок2);
		Если спНераспределенныхИгроков.РазмерСписка()=0 Тогда
			Возврат Результат;
		КонецЕсли;

		Для ж=1 По спВозможныхПар.РазмерСписка() Цикл
			текПара_2 = спВозможныхПар.ПолучитьЗначение(ж);
			Если текПара=текПара_2 Тогда Продолжить;		КонецЕсли;

			ПолучитьИгроковПары(текПара_2, Игрок1, Игрок2);
			Если (спНераспределенныхИгроков.НайтиЗначение(игрок1)=0) или (спНераспределенныхИгроков.НайтиЗначение(игрок2)=0)  Тогда
				Продолжить;
			КонецЕсли;

			Результат.ДобавитьЗначение(текПара_2);

			УдалитьИзСписка(спНераспределенныхИгроков, Игрок1, Игрок2);
			Если спНераспределенныхИгроков.РазмерСписка()=0 Тогда
				Возврат Результат;
			КонецЕсли;

		КонецЦикла;
	КонецЦикла;

	Возврат "Решений нет!";
КонецФункции	// ПолучитьПарыДляИгр 

  
Наверх
 
IP записан
 
berezdetsky
1c++ power user
Отсутствует


barba non facit sisadminum

Сообщений: 1986
Местоположение: Москва
Зарегистрирован: 19. Мая 2006
Пол: Мужской
Re: Разминка для головы. Оптимальный алгоритм.
Ответ #31 - 22. Мая 2010 :: 18:19
Печать  
При таком подходе для поиска больше, чем двух пар будут перебраны не все варианты. Вложенный цикл придётся вынести в рекурсивную функцию. Вариант без рекурсии мог бы выглядеть так:
Код
Выбрать все
	  Dim n = 6 ' 6-элементное множество
	  Dim k = 4 ' 4-элементные подмножества

	  Dim A(k - 1) As Integer

	  ' первое подмножество
	  For i = 1 To k
		A(i - 1) = i
	  Next

	  Dim p = k

	  Do While p >= 1
		For Each i In A
		    Console.Write("{0} ", i)
		Next
		Console.WriteLine()

		If A(k - 1) = n Then
		    p -= 1
		Else
		    p = k
		End If

		If p >= 1 Then
		    For i = k To p Step -1
			  A(i - 1) = A(p - 1) + i - p + 1
		    Next
		End If
	  Loop
 



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

пароль как коньяк, чем больше звездочек, тем лучше
Наверх
IP записан
 
JohnyDeath
1c++ power user
1c++ donor
Отсутствует



Сообщений: 3050
Местоположение: Волгоград
Зарегистрирован: 19. Мая 2006
Пол: Мужской
Re: Разминка для головы. Оптимальный алгоритм.
Ответ #32 - 22. Мая 2010 :: 18:37
Печать  
Цитата:
При таком подходе для поиска больше, чем двух пар будут перебраны не все варианты. Вложенный цикл придётся вынести в рекурсивную функцию.

Точно! Не зря я сомневался. Спасибо, что открыл глаза.

За алгоритм отдельное спасибо. Правда еще не въехал в него (видать спать пора).
а что такое "Dim n = 6 ' 6-элементное множество" ?  Нерешительный
  
Наверх
 
IP записан
 
berezdetsky
1c++ power user
Отсутствует


barba non facit sisadminum

Сообщений: 1986
Местоположение: Москва
Зарегистрирован: 19. Мая 2006
Пол: Мужской
Re: Разминка для головы. Оптимальный алгоритм.
Ответ #33 - 22. Мая 2010 :: 18:44
Печать  
JohnyDeath писал(а) 22. Мая 2010 :: 18:37:
а что такое "Dim n = 6 ' 6-элементное множество" ?  Нерешительный

Это алгоритм генерации k-элементных подмножеств n-элементного множества. Числа 4 и 6 взяты для примера. Написан на VB.NET. Результат работы в консоли: Цитата:
1 2 3 4
1 2 3 5
1 2 3 6
1 2 4 5
1 2 4 6
1 2 5 6
1 3 4 5
1 3 4 6
1 3 5 6
1 4 5 6
2 3 4 5
2 3 4 6
2 3 5 6
2 4 5 6
3 4 5 6
  

пароль как коньяк, чем больше звездочек, тем лучше
Наверх
IP записан
 
JohnyDeath
1c++ power user
1c++ donor
Отсутствует



Сообщений: 3050
Местоположение: Волгоград
Зарегистрирован: 19. Мая 2006
Пол: Мужской
Re: Разминка для головы. Оптимальный алгоритм.
Ответ #34 - 22. Мая 2010 :: 18:48
Печать  
Понял. Спасибо.

Смутила строчка
Код
Выбрать все
If A(k - 1) = n Then 

Т.е. конкретный элемент подмножества сравнивается с КОЛИЧЕСТВОМ элементов в множестве?
  
Наверх
 
IP записан
 
berezdetsky
1c++ power user
Отсутствует


barba non facit sisadminum

Сообщений: 1986
Местоположение: Москва
Зарегистрирован: 19. Мая 2006
Пол: Мужской
Re: Разминка для головы. Оптимальный алгоритм.
Ответ #35 - 22. Мая 2010 :: 18:51
Печать  
Не с количеством, а с последним элементом множества.
  

пароль как коньяк, чем больше звездочек, тем лучше
Наверх
IP записан
 
Переключение на Главную Страницу Страницы: [1] 
ОтправитьПечать