class Event { // интерфейс
public:
virtual double time() = 0; // когда потребуется внимание со стороны менеджера событий
virtual void process() = 0; // команда обработать событие
// virtual int type() = 0; // можно пристроить, если по какой-то причине надо отличать кресло от генератора клиентов
};
class EventSink { // интерфейс
virtual void add(Event& x);
}
class Shop;
class Chair : protected Event {
private:
double fTime;
bool fIsOccupied;
public:
Shop& shop;
virtual double time() override { return fTime; }
virtual void process() override;
{
что-то типа…
если shop.nWaiting != 0 {
--shop.nWaiting;
occupy(time);
} else {
isOccupied = false;
}
}
void occupy (double aTime) {
time = aTime + время обслуживания клиента
shop.manager.add(*this);
}
bool isOccupied() { return fIsOccupied; }
};
class CustomerGenerator : protected Event {
// Устроен аналогично Chair, служит для генерации потока клиентов
public:
virtual void process() override {
если shop.nWaiting == 0 и кресло свободно {
shop.chair.occupy(fTime);
} else {
++shop.nWaiting;
}
fTime += экспоненциальное время ожидания;
manager.add(*this);
}
void init() {
fTime = 0;
process();
}
};
class Shop {
public:
Chair chair; // можно несколько кресел
CustomerGenerator generator;
int nWaiting; // сколько человек в очереди
EventSink& manager;
}
class Manager : public EventSink {
Event* events[2]; // события отсортированы по времени
int nEvents;
void add(Event& x) override {
// вставить двоичным поиском x в нашу очередь; тут же можно сделать ограничение
// «обработать 1000 клиентов» или «работать 8 часов».
}
И самое главное — «жизненный цикл».
shop.generator.init();
Пока очередь не пуста…
• вытащить из неё событие
• process его!
}
<pluralRules nDecisions="3" unknownInt="2"> ← вариантов три; если ни одно из правил не подошло, брать последний («ворон»)
<rule mod="100" min="10" max="20" decide="2" /> ← остаток на 100 от 10 до 20 — «ворон»
<rule mod="10" min="1" max="1" decide="0" />
<rule mod="10" min="2" max="4" decide="1" />
</pluralRules>
trans := случайная перестановка чисел 0 … N−1
если N чётное
то M := N−1
иначе M := N
цикл 2half = false…true
цикл round = 0…M−1
цикл shift = 1…[M/2]
home := (round + shift) % M
away := (round + M − shift) % M
если (shift нечётное) xor 2half
обменять home, away
вывести trans[home], trans[away]
если N чётное
home := round
away := M
если (round нечётное) xor 2half
обменять home, away
вывести trans[home], trans[away]
алг рекурсия(узел: Узел)
длина_мас = 0
// Прогоним алгоритм для сыновей, рассчитаем длину массива
для всех сыновей (узел) → сын
рекурсия(сын) // ыгы, в основе банальный обход в глубину
длина_мас = макс(длина_мас, сын.границы.длина)
длина_мас = длина_мас + 1
разложить сыновей на плоскости, руководствуясь их массивами границ
и вашим чувством прекрасного; соответственно присвоить ИХ deltaX
(оставлю это как домашнее задание)
// Рассчитаем границы дли нашего узла
границы.установить_размер(длина_мас)
границы.заполнить(левая=+M, правая=—M)
полширины = узел.ширина / 2
границы[0] = (левая = −полширины, правая = узел.ширина − полширины)
для всех сыновей (узел) → сын
для i = [0 .. сын.границы.длина)
узел.границы[i+1].левая = мин(
узел.границы[i+1].левая, сын.границы[i].левая + сын.deltaX)
// если сыновья идут слева направо, этого хватает!
узел.границы[i+1].правая = сын.границы[i].правая + сын.deltaX
сын.границы.установить_размер(0) // массив больше не нужен
// Если же нужны точные координаты каждого узла…
алг уточнитьКоординаты(узел: Узел; Y: целое)
узел.коорд.Y = Y
Yсына = Y + высота_яруса
для всех сыновей (узел) → сын
сын.коорд.X = узел.коорд.X + сын.deltaX
уточнитьКоординаты(сын, Yсына)
for(int i = 0;i < Edges[v].size();i ++){
if(dfs(Edges[v].get(i)))return true;
}
цикл (i : все вершины)
если матрица_смежности[v, i]
если dfs(i)
return true;
UNVISITED = 0;
PARTLY_VISITED = 1;
VISITED = 2;
namespace {
const double dSafe = 30;
const int rSafe = dSafe / 2;
const double a = -0.3 * dSafe;
int toPixel(double x)
{
return floor(x + 0.5) + 200;
}
}
void TfmMain::drawPoint(double x, double y)
{
int xx = toPixel(x);
int yy = toPixel(y);
Canvas->Ellipse(xx - rSafe, yy - rSafe, xx + rSafe, yy + rSafe);
}
void __fastcall TfmMain::FormPaint(TObject *Sender)
{
Canvas->Brush->Style = bsClear;
Canvas->Pen->Color = clBlack;
double x = 0, y = 0;
drawPoint(x, y);
x += dSafe;
drawPoint(x, y);
for (int i = 0; i < 120; ++i) {
double r = sqrt(x*x + y*y);
double tx = a*x + r*y;
double ty = a*y - r*x;
double tLen = sqrt(tx*tx + ty*ty);
double k = dSafe / tLen;
x += tx * k;
y += ty * k;
drawPoint(x, y);
}
}
Если подвижных мостов мало, можно каждую вершину размножить в 2b экземплярах (b — кол-во мостов). Тогда пойдёт даже не Дейкстра, а обычный поиск в ширину.
Если два моста «сцеплены» друг с другом и наводятся/разводятся одновременно, то в b они идут одной штукой.
А если мостов много и 2b — непозволительная трата, тогда интересно. Думаю, ничего, кроме эвристик, не поможет. Например, может случиться так, что кратчайший путь от включателя до всех мостов, которыми он управляет, посуху. Или мосты (в смысле управляемые) — это мосты (в смысле теории графов). Или что-нибудь ещё.