Problem Summary

The wall is built on lattice posts inside a \(500\times 500\) square. The quantity to maximize is

$$\frac{\text{enclosed area}}{\text{wall length}}.$$

By symmetry, the full wall can be reconstructed from one quarter of the boundary, namely a monotone chain from the top midpoint to the right midpoint.

With

$$G=250,$$

we only optimize a quarter-chain from

$$ (0,G)\quad\text{to}\quad (G,0).$$

If this quarter-chain has area \(A\) under it and length \(L\), then the full symmetric wall has area \(4A\) and length \(4L\), so the global ratio is exactly

$$\frac{4A}{4L}=\frac{A}{L}.$$

Mathematical Approach

1) Why one quarter is enough.

The square and the objective are symmetric with respect to both coordinate axes through the center. Therefore an optimal wall can be assumed to be symmetric too. In the first quadrant, its boundary is a chain starting at the top midpoint \((0,G)\) and ending at the right midpoint \((G,0)\).

We may also assume this chain is monotone: \(x\) never decreases and \(y\) never increases. Any backtracking would increase perimeter without helping the enclosed area.

2) Why the chain can be taken convex.

If a local part of the chain bends the wrong way, replacing that dent by its chord increases or preserves the enclosed area while shortening the boundary. So an optimum must be convex in the quarter-square. Convexity means the slopes of successive segments are nondecreasing as we move from the top midpoint to the right midpoint.

3) Primitive step vectors are enough.

A segment from one lattice post to another with displacement

$$ (u,v),\qquad u,v\ge 0$$

passes through intermediate lattice posts whenever \(\gcd(u,v)>1\). Splitting such a segment at those intermediate posts does not change either its geometric length or the area under it. Therefore we only need primitive vectors

$$\gcd(u,v)=1.$$

The code includes the axis vectors \((1,0)\) and \((0,1)\) as well, so horizontal and vertical runs are still possible.

4) Coordinate transform used by the DP.

The actual quarter-chain lives in ordinary coordinates \((x,y)\) from \((0,G)\) to \((G,0)\). The implementation stores instead

$$j=G-y,$$

so the start point becomes \((0,0)\) and the endpoint becomes \((G,G)\). A geometric segment

$$ (x,y)\to(x+u,y-v)$$

therefore appears in the DP as

$$ (x,j)\to(x+u,j+v).$$

This is why the code fills `dp[x+u][j+v]` from `dp[x][j]`.

5) Exact area increment of one segment.

The area under one segment is the area of a trapezoid. If the segment goes from height \(y\) down to height \(y-v\) over horizontal distance \(u\), then

$$\Delta A=u\cdot\frac{y+(y-v)}{2}=u\left(y-\frac v2\right).$$

Since \(y=G-j\), this becomes

$$\Delta A=u\left(G-j-\frac v2\right).$$

This is exactly what the implementation computes as

$$u\left(G-\frac v2\right)-ju,$$

which explains the code lines `base_area = u * (GRID - 0.5 * v)` and the later `area_gain -= u` as \(j\) increases.

6) Exact length increment.

The boundary contribution of the segment is simply

$$\Delta L=\sqrt{u^2+v^2}.$$

So if a quarter-chain is described by a sequence of primitive vectors \((u_i,v_i)\), then

$$A=\sum_i \Delta A_i,\qquad L=\sum_i \sqrt{u_i^2+v_i^2}.$$

7) Fractional objective and Dinkelbach transform.

The target ratio is

$$\rho^*=\max \frac{A}{L}.$$

Instead of maximizing a ratio directly, fix a real parameter \(\lambda\) and maximize

$$F_\lambda=A-\lambda L.$$

For the optimal ratio \(\rho^*\), the maximum value of \(F_{\rho^*}\) is exactly \(0\). This is the standard Dinkelbach principle for fractional programming.

So the algorithm repeatedly solves the easier DP problem for a fixed \(\lambda\), obtains the best chain \((A,L)\), and updates

$$\lambda\leftarrow \frac{A}{L}.$$

When the update stops changing, we have reached the optimal ratio.

8) DP state and transition.

Let `score[x][j]` be the best value of

$$A-\lambda L$$

for a convex monotone chain ending at transformed point \((x,j)\), using only directions processed so far.

The vectors are sorted by increasing slope

$$\frac vu,$$

with \((1,0)\) first and \((0,1)\) last. This enforces nondecreasing slope and therefore convexity.

For one vector \((u,v)\), the transition is

$$dp[x+u,j+v]=\max\Bigl(dp[x+u,j+v],\ dp[x,j]+\Delta A-\lambda\Delta L\Bigr).$$

Because the update is performed in-place while the current vector is active, the same direction may be used repeatedly. That is exactly what we want for long straight portions of the chain.

9) Why sorting by slope avoids self-intersections.

All chosen segments move rightward and downward in actual coordinates, and their slopes are processed in nondecreasing order. This means the tangent direction of the chain only turns one way. Combined with monotonicity, the quarter-boundary stays convex and cannot self-intersect.

Worked Geometric Interpretation

Suppose the quarter-chain contains a single diagonal step from \((175,250)\) to \((250,175)\), together with the horizontal and vertical parts needed to connect \((0,250)\) to \((250,0)\). This is exactly the kind of “cut off a corner” example described in the problem statement. The DP can represent that chain using repeated \((1,0)\), then one copy of \((75,75)\) split into primitive slope-\(1\) steps, then repeated \((0,1)\).

The area under that chain is the quarter-area of the final enclosed wall, and the quarter-length is the corresponding quarter of the full boundary. The optimization simply searches all such convex monotone quarter-chains and chooses the one with maximum \(A/L\).

Algorithm

1) Build all primitive vectors \((u,v)\) with \(0\le u,v\le G\), plus \((1,0)\) and \((0,1)\).

2) Sort them by slope \(v/u\).

3) For a fixed \(\lambda\), run a DP on the \((G+1)\times(G+1)\) grid of transformed endpoints.

4) Recover the optimal quarter-area \(A\) and quarter-length \(L\) at state \((G,G)\).

5) Update \(\lambda\leftarrow A/L\) and repeat until convergence.

Complexity Analysis

Let \(K\) be the number of primitive directions. One DP solve costs

$$O(KG^2)$$

time and

$$O(G^2)$$

memory. The outer Dinkelbach iteration converges in only a small number of rounds, so the full computation is practical.

Checks And Final Result

The C++ program converges to

$$132.52756426,$$

which is the required maximum area-to-perimeter ratio rounded to eight decimal places.

Further Reading

  1. Problem page: https://projecteuler.net/problem=314
  2. Fractional programming / Dinkelbach method: https://en.wikipedia.org/wiki/Fractional_programming
  3. Primitive lattice vectors: https://en.wikipedia.org/wiki/Coprime_integers

Problemzusammenfassung

Die Mauer wird auf Gitterpunkten innerhalb eines \(500\times500\)-Quadrats gebaut. Maximiert werden soll

$$\frac{\text{eingeschlossene Flaeche}}{\text{Mauerlaenge}}.$$

Wegen der Symmetrie genuegt es, nur eine Viertelkurve von \((0,G)\) nach \((G,0)\) mit \(G=250\) zu optimieren. Wenn diese Viertelkette Flaeche \(A\) und Laenge \(L\) besitzt, dann hat die volle symmetrische Mauer Quotient \(A/L\).

Mathematischer Ansatz

1) Monotone konvexe Viertelkette. Eine optimale Loesung kann als monotone Kette angenommen werden: \(x\) waechst, \(y\) faellt. Rueckwaertsbewegungen vergroessern nur den Umfang. Ebenso kann die Kette konvex angenommen werden, denn eine „Delle“ laesst sich durch die Sehne ersetzen, was mehr oder gleiche Flaeche bei kuerzerer Laenge liefert.

2) Primitive Vektoren reichen aus. Ein Segment mit Verschiebung \((u,v)\) und \(\gcd(u,v)>1\) laeuft durch innere Gitterpunkte. Seine Zerlegung in primitive Teilsegmente veraendert weder Geometrie noch Laenge noch Flaeche. Deshalb muessen nur primitive Richtungen mit \(\gcd(u,v)=1\) betrachtet werden; die Achsenvektoren \((1,0)\) und \((0,1)\) werden explizit hinzugefuegt.

3) Transformierte Koordinaten. Die reale Kette laeuft von \((0,G)\) nach \((G,0)\). Der Code speichert stattdessen

$$j=G-y,$$

sodass Start und Ziel zu \((0,0)\) bzw. \((G,G)\) werden. Ein geometrischer Schritt

$$ (x,y)\to(x+u,y-v)$$

entspricht daher im DP

$$ (x,j)\to(x+u,j+v).$$

4) Exakter Flaechenzuwachs. Ein Segment erzeugt unter sich ein Trapez. Dessen Flaeche ist

$$\Delta A=u\cdot\frac{y+(y-v)}{2}=u\left(y-\frac v2\right).$$

Mit \(y=G-j\) wird das zu

$$\Delta A=u\left(G-j-\frac v2\right).$$

Genau deshalb benutzt der Code `base_area = u * (GRID - 0.5 * v)` und vermindert diesen Gewinn beim Durchlauf jeder Zeile um \(u\).

5) Laengenzuwachs. Fuer denselben Schritt gilt

$$\Delta L=\sqrt{u^2+v^2}.$$

6) Dinkelbach-Transformation. Anstelle von \(\max A/L\) wird fuer festes \(\lambda\)

$$F_\lambda=A-\lambda L$$

maximiert. Beim optimalen Quotienten \(\rho^*\) ist das Maximum von \(F_{\rho^*}\) gleich \(0\). Deshalb wird nach jeder DP-Runde

$$\lambda\leftarrow A/L$$

gesetzt.

7) DP-Zustand und Steigungsordnung. Die Vektoren werden nach wachsender Steigung \(v/u\) sortiert. Damit sind nur nichtfallende Steigungen erlaubt, also konvexe Ketten. Der Zustand `dp[x,j]` speichert den besten Wert von \(A-\lambda L\) fuer einen Endpunkt \((x,j)\). Der Uebergang lautet

$$dp[x+u,j+v]=\max\Bigl(dp[x+u,j+v],dp[x,j]+\Delta A-\lambda\Delta L\Bigr).$$

In-Place-Updates erlauben auch mehrfachen Gebrauch derselben Richtung, was lange gerade Abschnitte abdeckt.

Komplexitaetsanalyse

Mit \(K\) primitiven Richtungen kostet eine DP-Runde \(O(KG^2)\) Zeit und \(O(G^2)\) Speicher. Nur wenige aeussere Iterationen sind noetig.

Kontrollen Und Endergebnis

Die Implementierung konvergiert zu

$$132.52756426.$$

Weiterfuehrende Hinweise

  1. Problemseite: https://projecteuler.net/problem=314
  2. Fractional Programming / Dinkelbach: https://en.wikipedia.org/wiki/Fractional_programming
  3. Primitive Gittervektoren: https://de.wikipedia.org/wiki/Teilerfremdheit

Problem Özeti

Duvar, \(500\times500\) kare icindeki izgara direkleri uzerinden kuruluyor ve maksimize edilen nicelik

$$\frac{\text{cevrilen alan}}{\text{duvar uzunlugu}}$$

orani. Simetri sayesinde tum duvari degil, sadece bir ceyrek siniri optimize etmek yetiyor. \(G=250\) olmak uzere bu ceyrek zincir

$$ (0,G)\to(G,0)$$

arasinda ilerleyen artan bir yoldur. Bu zincirin altindaki alan \(A\), uzunlugu \(L\) ise tum seklin orani yine \(A/L\) olur.

Matematiksel Yaklaşım

1) Neden tek ceyrek yeterli? Problem hem yatay hem dikey eksene gore simetrik oldugu icin optimal duvari da ayni simetriyle alabiliriz. Ilk ceyrekteki sinir, ust orta noktadan sag orta noktaya giden tek bir zincirdir.

2) Zincir neden monoton ve konveks alınabilir? Geriye giden bir parca cevreyi uzatir ama alana yardim etmez. Benzer sekilde iceri dogru bir “cukur” varsa onu dogru kirisle degistirmek alani azaltmadan cevreyi kisaltir. Bu nedenle optimum zincir monoton ve konvekstir; yani egimler ilerledikce azalmaz.

3) Neden sadece ilkel vektorler? Bir kenarin yer degistirmesi \((u,v)\) olsun. Eger

$$\gcd(u,v)>1$$

ise bu dogru parcasi aradaki diger izgara noktalarindan da geciyordur. Bu parcayi ayni dogru uzerindeki daha kucuk primitive adimlara bolmek ne uzunlugu ne de alani degistirir. Dolayisiyla sadece

$$\gcd(u,v)=1$$

olan yonler yeterlidir. Kod, yatay ve dikey kismi kurabilmek icin \((1,0)\) ve \((0,1)\) yonlerini de dahil eder.

4) Kodun kullandigi koordinat donusumu. Gercek ceyrek zincir \((0,G)\)'den \((G,0)\)'a gider. Kod ise

$$j=G-y$$

tanimini kullanir. Boylece baslangic \((0,0)\), bitis \((G,G)\) olur. Geometrik olarak

$$ (x,y)\to(x+u,y-v)$$

adimi, DP'de

$$ (x,j)\to(x+u,j+v)$$

seklinde gorunur.

5) Alan artisi neden trapez alanı? Bir segmentin altinda kalan alan bir trapezdir. Baslangic yuksekligi \(y\), bitis yuksekligi \(y-v\), yatay uzunluk \(u\) ise

$$\Delta A=u\cdot\frac{y+(y-v)}{2}=u\left(y-\frac v2\right).$$

\(y=G-j\) oldugu icin

$$\Delta A=u\left(G-j-\frac v2\right)$$

elde edilir. Kodun

$$u\left(G-\frac v2\right)-ju$$

hesabi tam olarak budur. `area_gain -= u` satiri da \(j\) bir arttiginda alan kazancinin neden \(u\) kadar azaldigini aciklar.

6) Cevre artisi. Ayni segmentin cevreye katkisi dogrudan

$$\Delta L=\sqrt{u^2+v^2}$$

olur.

7) Oran yerine fark maksimize etme. Hedef

$$\rho^*=\max\frac{A}{L}$$

oldugu icin Dinkelbach donusumu kullanilir. Sabit \(\lambda\) icin

$$F_\lambda=A-\lambda L$$

maksimize edilir. Optimal oranda bu degerin en buyugu \(0\)'dir. Bu yuzden her DP turunden sonra

$$\lambda\leftarrow\frac{A}{L}$$

guncellenir.

8) DP durumu ve gecis. `dp[x,j]`, o ana kadar islenen yonlerle \((x,j)\) noktasina gelen en iyi

$$A-\lambda L$$

skorudur. Yonler artan egime gore siralanir; bu da zincirin konveks kalmasini saglar. Gecis:

$$dp[x+u,j+v]=\max\Bigl(dp[x+u,j+v],dp[x,j]+\Delta A-\lambda\Delta L\Bigr).$$

Ayni yonun tekrar tekrar kullanilabilmesi icin guncelleme in-place yapilir; boylece uzun dogrusal kisimlar da modellenir.

Karmaşıklık Analizi

\(K\) adet primitive yon olsun. Bir DP turu

$$O(KG^2)$$

zaman ve

$$O(G^2)$$

bellek kullanir. Dis Dinkelbach dongusu cok az adimda yakinser.

Kontroller Ve Nihai Sonuc

C++ kodunun yakinadigi nihai oran

$$132.52756426$$

olarak yazdirilir.

Ileri Okuma

  1. Problem metni: https://projecteuler.net/problem=314
  2. Fractional programming / Dinkelbach: https://en.wikipedia.org/wiki/Fractional_programming
  3. Primitive kafes vektorleri: https://tr.wikipedia.org/wiki/Aralarında_asal

Resumen del Problema

La pared se construye sobre postes de una red dentro de un cuadrado \(500\times500\). El objetivo es maximizar

$$\frac{\text{area encerrada}}{\text{longitud de la pared}}.$$

Por simetria basta optimizar una sola cadena de cuarto de borde, desde \((0,G)\) hasta \((G,0)\) con \(G=250\). Si esa cadena tiene area \(A\) bajo ella y longitud \(L\), entonces la figura completa tiene la misma razon \(A/L\).

Enfoque Matematico

1) Cadena monotona y convexa. Una solucion optima puede suponerse monotona: \(x\) aumenta y \(y\) disminuye. Cualquier retroceso solo empeora el perimetro. Tambien puede suponerse convexa: una hendidura local puede reemplazarse por su cuerda, con area no menor y menor longitud.

2) Solo hacen falta vectores primitivos. Si un segmento tiene desplazamiento \((u,v)\) con \(\gcd(u,v)>1\), pasa por puntos intermedios de la reticula. Dividirlo en subsegmentos colineales primitivos no cambia ni area ni longitud. Por eso el algoritmo enumera solo vectores primitivos, junto con \((1,0)\) y \((0,1)\).

3) Cambio de coordenadas. La cadena real va de \((0,G)\) a \((G,0)\). El codigo usa

$$j=G-y,$$

de modo que el problema se convierte en una ruta de \((0,0)\) a \((G,G)\). Un paso geometrico

$$ (x,y)\to(x+u,y-v)$$

se escribe en DP como

$$ (x,j)\to(x+u,j+v).$$

4) Incremento exacto de area. El area bajo un segmento es un trapecio:

$$\Delta A=u\cdot\frac{y+(y-v)}{2}=u\left(y-\frac v2\right).$$

Sustituyendo \(y=G-j\),

$$\Delta A=u\left(G-j-\frac v2\right).$$

Esto explica directamente el `base_area` del programa.

5) Incremento de longitud.

Se tiene simplemente

$$\Delta L=\sqrt{u^2+v^2}.$$

6) Transformacion de Dinkelbach. En lugar de maximizar \(A/L\), para un \(\lambda\) fijo se maximiza

$$F_\lambda=A-\lambda L.$$

En el optimo, el valor maximo de \(F_{\lambda^*}\) es \(0\), y entonces \(\lambda^*=A/L\). Por eso el algoritmo actualiza repetidamente

$$\lambda\leftarrow A/L.$$

7) Estado DP. `dp[x,j]` guarda el mejor valor de \(A-\lambda L\) para una cadena convexa que termina en \((x,j)\). Los vectores se procesan en orden de pendiente creciente \(v/u\), lo que obliga a que las pendientes de la cadena no decrezcan. La transicion es

$$dp[x+u,j+v]=\max\Bigl(dp[x+u,j+v],dp[x,j]+\Delta A-\lambda\Delta L\Bigr).$$

Complejidad

Si \(K\) es el numero de direcciones primitivas, una ronda DP cuesta \(O(KG^2)\) tiempo y \(O(G^2)\) memoria. La iteracion exterior converge en muy pocas rondas.

Resultado Final

El programa converge a

$$132.52756426.$$

Lecturas

  1. Problema: https://projecteuler.net/problem=314
  2. Programacion fraccional: https://es.wikipedia.org/wiki/Programación_fraccional
  3. Numeros coprimos: https://es.wikipedia.org/wiki/Números_coprimos

问题概述

围墙建在 \(500\times500\) 正方形内的格点上,目标是最大化

$$\frac{\text{围成的面积}}{\text{围墙长度}}.$$

利用对称性,只需求解一条四分之一边界链:从 \((0,G)\) 到 \((G,0)\),其中 \(G=250\)。若这条四分之一链下方的面积为 \(A\),长度为 \(L\),则完整对称图形的比值仍然是 \(A/L\)。

数学方法

1) 单调且凸的四分之一边界。 最优边界可假设为单调链:\(x\) 递增、\(y\) 递减。任何回头都会增加周长而无助于面积。它还可假设为凸链,因为局部凹陷总可以被弦替代,得到不更小的面积和更短的长度。

2) 只需原始向量。 若位移 \((u,v)\) 满足 \(\gcd(u,v)>1\),则该线段会经过中间格点。把它拆成若干共线的原始段不会改变总长度与总面积。因此只需要枚举

$$\gcd(u,v)=1$$

的方向,再额外加入轴向步 \((1,0)\) 和 \((0,1)\)。

3) 代码中的坐标变换。

真实链从 \((0,G)\) 走到 \((G,0)\)。代码令

$$j=G-y,$$

于是起点变成 \((0,0)\),终点变成 \((G,G)\)。几何步

$$ (x,y)\to(x+u,y-v)$$

在 DP 中就写成

$$ (x,j)\to(x+u,j+v).$$

4) 面积增量为什么是梯形面积。

一条线段下方的面积是梯形:

$$\Delta A=u\cdot\frac{y+(y-v)}{2}=u\left(y-\frac v2\right).$$

代入 \(y=G-j\) 得

$$\Delta A=u\left(G-j-\frac v2\right),$$

这正好对应代码中的 `base_area` 与按行递减的 `area_gain`。

5) 长度增量。

对应边长就是

$$\Delta L=\sqrt{u^2+v^2}.$$

6) Dinkelbach 变换。

为了最大化 \(A/L\),固定 \(\lambda\) 后改为最大化

$$F_\lambda=A-\lambda L.$$

当 \(\lambda\) 等于最优比值时,\(F_\lambda\) 的最大值恰好为 \(0\)。因此每轮 DP 之后更新

$$\lambda\leftarrow A/L.$$

7) DP 状态。

`dp[x,j]` 表示到达变换坐标 \((x,j)\) 时,\(A-\lambda L\) 的最佳值。所有向量按斜率 \(v/u\) 递增处理,从而强制边界斜率不下降,也就保证了凸性。转移为

$$dp[x+u,j+v]=\max\Bigl(dp[x+u,j+v],dp[x,j]+\Delta A-\lambda\Delta L\Bigr).$$

复杂度分析

若原始方向总数为 \(K\),一次 DP 的时间复杂度为 \(O(KG^2)\),空间复杂度为 \(O(G^2)\)。外层迭代次数很少。

最终结果

程序最终收敛到

$$132.52756426.$$

延伸阅读

  1. 题目页面: https://projecteuler.net/problem=314
  2. 分式规划: https://en.wikipedia.org/wiki/Fractional_programming
  3. 互素与原始向量: https://zh.wikipedia.org/wiki/互质

Краткое описание

Стена строится по узлам решетки внутри квадрата \(500\times500\), и требуется максимизировать

$$\frac{\text{площадь}}{\text{длина стены}}.$$

По симметрии достаточно рассматривать только одну четверть границы: цепь от \((0,G)\) до \((G,0)\), где \(G=250\). Если для этой четверти площадь под цепью равна \(A\), а длина равна \(L\), то для всей симметричной фигуры отношение тоже равно \(A/L\).

Математический подход

1) Монотонная выпуклая четверть. Оптимальную цепь можно считать монотонной: \(x\) растет, \(y\) падает. Любой возврат назад только увеличивает периметр. Ее также можно считать выпуклой: локальную вмятину можно заменить хордой, сохранив или увеличив площадь и укоротив границу.

2) Достаточно примитивных векторов. Если смещение \((u,v)\) имеет \(\gcd(u,v)>1\), то соответствующий отрезок проходит через промежуточные узлы решетки. Разбиение его на примитивные коллинеарные части не меняет ни длину, ни площадь. Значит, нужны только векторы с \(\gcd(u,v)=1\), плюс осевые шаги \((1,0)\) и \((0,1)\).

3) Координатное преобразование. Реальная цепь идет от \((0,G)\) к \((G,0)\). В коде используется

$$j=G-y,$$

поэтому старт становится \((0,0)\), а финиш \((G,G)\). Геометрический переход

$$ (x,y)\to(x+u,y-v)$$

в DP записывается как

$$ (x,j)\to(x+u,j+v).$$

4) Приращение площади. Площадь под одним сегментом равна площади трапеции:

$$\Delta A=u\cdot\frac{y+(y-v)}{2}=u\left(y-\frac v2\right).$$

После подстановки \(y=G-j\) получаем

$$\Delta A=u\left(G-j-\frac v2\right),$$

что точно соответствует формуле в программе.

5) Приращение длины.

Длина сегмента равна

$$\Delta L=\sqrt{u^2+v^2}.$$

6) Преобразование Динкельбаха. Вместо прямого максимума \(A/L\) фиксируется \(\lambda\) и максимизируется

$$F_\lambda=A-\lambda L.$$

Для оптимального отношения \(\lambda^*\) максимум \(F_{\lambda^*}\) равен нулю. Поэтому после каждого запуска DP обновляется

$$\lambda\leftarrow A/L.$$

7) Состояние DP. `dp[x,j]` хранит лучший показатель \(A-\lambda L\) для выпуклой цепи, оканчивающейся в \((x,j)\). Направления обрабатываются в порядке неубывающего наклона \(v/u\), что и обеспечивает выпуклость. Переход:

$$dp[x+u,j+v]=\max\Bigl(dp[x+u,j+v],dp[x,j]+\Delta A-\lambda\Delta L\Bigr).$$

Сложность

Если \(K\) - число примитивных направлений, одна итерация DP требует \(O(KG^2)\) времени и \(O(G^2)\) памяти. Внешних итераций немного.

Итог

Программа сходится к значению

$$132.52756426.$$

Дополнительные материалы

  1. Условие: https://projecteuler.net/problem=314
  2. Fractional programming / Dinkelbach: https://en.wikipedia.org/wiki/Fractional_programming
  3. Взаимно простые числа: https://ru.wikipedia.org/wiki/Взаимно_простые_числа

ملخص المسألة

يُبنى الجدار على نقاط شبكة داخل مربع \(500\times500\)، والمطلوب تعظيم

$$\frac{\text{المساحة المحصورة}}{\text{طول الجدار}}.$$

بسبب التماثل يكفي أن نحسن ربعًا واحدًا فقط من الحد: سلسلة تبدأ من \((0,G)\) وتنتهي عند \((G,0)\) حيث \(G=250\). إذا كانت المساحة تحت هذا الربع هي \(A\) وطوله \(L\)، فإن النسبة في الشكل الكامل تساوي أيضًا \(A/L\).

المنهج الرياضي

1) ربع حد أحادي ومحدب. يمكن افتراض أن الحد الأمثل أحادي: \(x\) يزداد و\(y\) ينخفض. أي رجوع للخلف يزيد المحيط بلا فائدة. كما يمكن افتراض أنه محدب، لأن أي انبعاج داخلي يمكن استبداله بوتر يعطي مساحة لا تقل ومحيطًا أقصر.

2) لماذا تكفي المتجهات الأولية. إذا كان الإزاحة \((u,v)\) تحقق \(\gcd(u,v)>1\)، فإن القطعة المستقيمة تمر عبر نقاط شبكة وسيطة. تقسيمها إلى قطع أولية على الخط نفسه لا يغير لا الطول ولا المساحة. لذلك يكفي تعداد المتجهات ذات

$$\gcd(u,v)=1,$$

مع إضافة \((1,0)\) و\((0,1)\) من أجل الأجزاء الأفقية والعمودية.

3) تحويل الإحداثيات في الكود. الحد الحقيقي يسير من \((0,G)\) إلى \((G,0)\). الكود يعرّف

$$j=G-y,$$

فتصبح البداية \((0,0)\) والنهاية \((G,G)\). وبذلك فإن الانتقال الهندسي

$$ (x,y)\to(x+u,y-v)$$

يظهر في DP بالشكل

$$ (x,j)\to(x+u,j+v).$$

4) زيادة المساحة هي مساحة شبه منحرف.

المساحة تحت قطعة واحدة هي

$$\Delta A=u\cdot\frac{y+(y-v)}{2}=u\left(y-\frac v2\right).$$

وبالتعويض عن \(y=G-j\) نحصل على

$$\Delta A=u\left(G-j-\frac v2\right),$$

وهو بالضبط ما تحسبه الصيغة الموجودة في البرنامج.

5) زيادة الطول.

طول القطعة يساوي ببساطة

$$\Delta L=\sqrt{u^2+v^2}.$$

6) تحويل Dinkelbach. بدل تعظيم \(A/L\) مباشرة، نثبت \(\lambda\) ونعظم

$$F_\lambda=A-\lambda L.$$

عند النسبة المثلى يكون أكبر مقدار لهذه الدالة مساويًا للصفر. لذلك بعد كل جولة DP يتم تحديث

$$\lambda\leftarrow \frac{A}{L}.$$

7) حالة DP. القيمة `dp[x,j]` تمثل أفضل قيمة لـ \(A-\lambda L\) لسلسلة محدبة تنتهي عند \((x,j)\). تُرتب الاتجاهات حسب الميل \(v/u\) ترتيبًا تصاعديًا، وبذلك نفرض أن الميول لا تنخفض، أي أن السلسلة تبقى محدبة. والانتقال هو

$$dp[x+u,j+v]=\max\Bigl(dp[x+u,j+v],dp[x,j]+\Delta A-\lambda\Delta L\Bigr).$$

تحليل التعقيد

إذا كان عدد الاتجاهات الأولية هو \(K\)، فإن كل جولة DP تكلف \(O(KG^2)\) زمنًا و\(O(G^2)\) ذاكرة. عدد الجولات الخارجية صغير.

النتيجة النهائية

القيمة التي يتقارب إليها البرنامج هي

$$132.52756426.$$

مراجع إضافية

  1. صفحة المسألة: https://projecteuler.net/problem=314
  2. البرمجة الكسرية / طريقة Dinkelbach: https://en.wikipedia.org/wiki/Fractional_programming
  3. الأعداد المتباينة أوليًا: https://ar.wikipedia.org/wiki/عددان_أوليان_نسبيا