Переключение на Главную Страницу Страницы: [1] 2 3  ОтправитьПечать
Очень популярная тема (более 25 ответов) Разминка для головы. Оптимальный алгоритм. (число прочтений - 7249 )
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 записан
 
Переключение на Главную Страницу Страницы: [1] 2 3 
ОтправитьПечать