Матч
430, Продавцы картин (ImageTraders)
Дивизион 2,
Уровень 3
Имеется общество любителей искусства,
которые время от времени продают и покупают картины друг у друга. Каждая
продажа картины происходит согласно следующим правилам:
·
Цена картины, по которой она продается, должна быть не меньше цены, по
которой она покупалась;
·
Ни один продавец не может купить одну и ту же картину дважды.
Некая новая картина появилась на
рынке, и ее приобрел торговец с номером 0. Далее эта картина будет
перепродаваться среди имеющихся любителей. Ячейка массива price[i][j]
содержит цену, за которую i - ый
торговец готов продать эту картину j
- ому. Значение ‘0’ является наименьшей ценой, а ‘9’ – наибольшей. Необходимо
определить наибольшее количество продавцов (включая 0 и последнего), которые
могут владеть новой картиной.
Класс: ImageTraders
Метод: int
maxOwners(vector<string> price)
Ограничения: price содержит в точности n элементов, 2 £ n £ 15, каждый элемент price
содержит n символов ‘0’ – ‘9’.
Вход. Массив price содержит информацию о ценах продажи новой картины между
продавцами.
Выход. Наибольшее количество продавцов (включая нулевого и
последнего), которые могут владеть новой картиной.
Пример входа
price |
{"01", "10"} |
{"022", "101", "110"} |
{"01231", "00231", "00031", "00002", "00000"} |
Пример выхода
2
2
4
РЕШЕНИЕ
динамическое программирование, маски подмножеств
Состоянием будем называть тройку (mask, i, p),
обозначающую тот факт, что продавец с номером i заплатил за новую картину цену p, причем картиной не владели только те продавцы, на местах которых
в mask стоят 0. Например, состояние
(00101112, 3, 5) говорит о том, что третий продавец приобрел картину
стоимостью 5, причем картиной еще не владели 3, 5 и 6 продавцы (крайняя справа единица
в маске соответствует нулевому продавцу).
Начальное состояние
имеет вид (1, 0, 0) – нулевой продавец приобрел картину за цену 0 и может
продать ее любому из продавцов.
Функция
solve(mask, last, id) возвращает
наибольшее количество продавцов, которые могут владеть новой картиной, если на
данный момент продавец с номером last
приобрел картину стоимостью id, а
продавать картину можно только тем продавцам, которым в маске mask соответствуют нули. Если текущий
продавец никому продать картину не может, то наибольшая длина пути картины
равна количеству единиц в двоичном коде числа mask.
Совершаем
перебор всех возможных продаж с запоминанием всех состояний в массиве m.
ПРИМЕР
Рассмотрим второй пример. Нулевой
продавец может продать имеющуюся изначально у него картину или первому или
второму продавцу за сумму 2. Таким образом при продаже первому продавцу мы
переходим из начального состояния (1, 0, 0) в (112,
1, 2). Если нулевой продавец продаст картину второму продавцу, то переходим в
состояние (1012, 2, 2). В обоих
случаях дальнейшая продажа картин не возможна: ни первый ни второй продавец не
в состоянии перекупить картину ценой 2.
ПРОГРАММА
#include <cstdio>
#include <string>
#include <vector>
#include <memory>
using namespace std;
int n,m[1<<15][10][15];
vector<string> P;
int ones(int n)
{
int c=0;
while(n) c++,n=n&(n-1);
return c;
}
int solve(int mask, int last, int id)
{
int temp,i,&ret = m[mask][last][id];
if (ret) return ret;
ret = ones(mask);
for(i = 0; i < n; i++)
if(!(mask & 1<<i) &&
(P[id][i] -'0') >= last )
{
temp = solve(mask | 1<<i , P[id][i] -'0',
i);
if (temp > ret) ret = temp;
}
return ret;
}
class ImageTraders
{
public:
int maxOwners(vector<string> price)
{
memset(m,0,sizeof(m));
P = price; n = (int)price.size();
return solve(1,0,0);
}
};