və ardıcıl olaraq robot tərəfindən yığılacaq iki butulkadır. Robot butulka -nı götürdükdən sonra onu masanın dörd kənarından birinə aparmalı və atmalıdır. Yalnız bundan sonra robot butulka -nin arxasınca gedə bilər. Robotun A(x_i, y_i) nöqtəsindən B(x_j, y_j) nöqtəsinə ən qısa yolunu tapmalıyıq ki, masanın kənarından keçməsi məcburidir.
AK+KB məsafəsi AK+KP=AP. A(x_i, y_i) və P(x_j,-y_j) nöqtələrinin koordinatlarını bilsək, məsafəni hesablaya bilərik
AL+LB məsafəsi AL+LQ=AQ. nöqtəsinin koordinatı w + (w-x_j) = 2w-x_j. A(x_i, y_i) və Q(2w-x_j,y_j) nöqtələrinin koordinatlarını bilsək, məsafəni hesablaya bilərik
AE+EB məsafəsi AE+ET=AT. A(x_i, y_i) və T(-x_j, y_j) nöqtələrinin koordinatlarını bilsək, məsafəni hesablaya bilərik
AD+DB məsafəsi AD+DS=AS. nöqtəsinin koordinatı l + (l-y_j) = 2l-y_j. A(x_i, y_i) və S(x_j,2l-y_j) nöqtələrinin koordinatlarını bilsək, məsafəni hesablaya bilərik
Robotun masanın kənarından atmaq üçün (x_i, y_i) nöqtəsində yerləşən butulkaya gedərkən keçməli olduğu ən qısa məsafəni tapmalıyıq. Bu məsafə dörd qiymətdən ən kiçiyinə bərabərdir:
Məhz bu yolu robot axırıncı butulkanı atmaq üçün gedəcək.
Robotun ilkin mövqeyi və bütün butulkaların koordinatları məlumdur. Qrafda düşünək ki, sıfırıncı zirvə robotun ilkin mövqeyinə, yerdə qalan zirvələr isə butulkalara uyğun gəlir. Sıfırıncı zirvə ilə hər biri arasında məsafə müvafiq nöqtələr arasında Evklid məsafəsi ilə müəyyənləşdirilir. İki butulka və arasındakı məsafə robotun butulka -dən butulka -ə masanın kənarında mütləq olaraq keçməli olduğu minimum yol ilə təyin edilir. Masanın üzərində butulka olduğunu nəzərə alaraq, bu qraf n+1 zirvəli olacaqdır.
Daha sonra bu qrafda minimal uzunluqlu Hamiltonian yolu tapmaq lazımdır. Robot sonuncu butulkaya çatdıqdan sonra yolun ümumi uzunluğuna həmin butulkanın masanın kənarından atılması üçün lazım olan məsafə əlavə edilməlidir. Hamiltonian yol axtarışını O(n^2 \cdot 2^n) asimptotik mürəkkəbliklə maskalar ilə dinamik proqramlaşdırma vasitəsilə həyata keçirilir.
Misal
Burada robotun ilkin mövqeyi və butulkaların koordinatları verilmişdir.
Robotun ən qısa yolunun uzunluğu
Alqoritmin tətbiqi
Konstant göy dəyəri ilə qəy et (sonsuzluq), və konstant — Hamiltonian yolda maksimum nöqtələr sayını təyin edir.
#define INF 1e18
#define MAX 20Dinamik şəkildə hesablanacaq dəyərinə təyin olunan massivini eləcə də butulkanın koordinatları x_i, y_i~(1 \le i \le n) saxlanan nöqtələrdə elan edək. Robotun ilkin mövqeyini x_0, y_0 nöqtəsində saxlayırıq.
double dp[1 << MAX][MAX + 1];
double x[MAX], y[MAX], m[MAX][MAX];solve funksiyası dp(S, last) dəyərini hesablayır — çoxluğunda olan bütün nöqtələri keçərək, zirvəsində bitirmək üçün lazım olan minimum məsafədir. çoxluğu tam sayı ilə kodlaşdırılır. Onda:
burada
m[i][last] — və nöqtələri arasındaki məsafə,
S\setminus {last} = mask~\^{}~(1<< last) — isdəkləri olmayan çoxluğu.
dp[mask][last] hüceyrəsinə uyğun olan dəyişən , dəyişəndə dp[mask][last] dəyişimləri avtomatik olaraq yenilənir.
double solve(int mask, int last)
{
double &res = dp[mask][last];
if (res == INF)
{
mask ^= (1 << last);
for (int i = 1; i < n; i++)
if ((mask & (1 << i)) && (i != last))
res = min(res, solve(mask, i) + m[i][last]);
}
return res;
}f funksiyası (x[i], y[i]) nöqtəsindən masanın kənarına qədər ən qısa məsafəni qaytarır.
double f(int i)
{
return min(min(x[i], y[i]), min(l - y[i], w - x[i]));
}dist funksiyası (x[i], y[i]) və (x[j], y[j]) nöqtələri arasındakı məsafəni qaytarır.
double dist(int i, int j)
{
return sqrt((x[i] - x[j])*(x[i] - x[j]) +
(y[i] - y[j])*(y[i] - y[j]));
}Proqramın əsas hissəsi. Masa ölçülərini və oxuyuruq.
scanf("%d %d", &w, &l);Butulkaların sayı və onların koordinatlarını (x[i], y[i]) oxuyuruq.
scanf("%d", &n);
for (i = 1; i <= n; i++)
scanf("%lf %lf", &x[i], &y[i]);Robotun ilkin koordinatlarını (x[0], y[0]) nöqtəsində saxlayırıq.
scanf("%lf %lf", &x[0], &y[0]); -ə əlavə olaraq robotun ilkin mövqeyinə uyğun sıfırıncı zirvəni əlavə edib, artıq bir artırılır və ümumi qrafda zirvə sayı olur. Qrafiyada zirvələr 0, 1, ..., n - 1 olaraq nömrələnir.
n++;Butulkalar arasında cüt-cüt məsafələri hesablayırıq. İki butulka və arasındakı məsafə robotun butulka -dən butulka -ə masanın kənarına mütləq olaraq keçərək gedəcək minimum yolla təyin edilir.
for (i = 1; i < n - 1; i++)
for (j = i + 1; j < n; j++)
m[i][j] = m[j][i] =
min(
min(sqrt((x[i] + x[j])*(x[i] + x[j]) + (y[i] - y[j])*(y[i] - y[j])),
sqrt((2 * w - x[i] - x[j])*(2 * w - x[i] - x[j]) +
(y[i] - y[j])*(y[i] - y[j]))),
min(sqrt((x[i] - x[j])*(x[i] - x[j]) + (y[i] + y[j])*(y[i] + y[j])),
sqrt((x[i] - x[j])*(x[i] - x[j]) +
(2 * l - y[i] - y[j])*(2 * l - y[i] - y[j])))
);İlkin olaraq dp(S, i) dəyərləri məlum olmadığından, onlara sonsuzluq dəyəri atanır.
for (i = 0; i < 1 << n; i++)
for (j = 0; j < n; j++)
dp[i][j] = INF;çoxluğuna maskası uyğundur. dp(\{0\}, 0) = 0 edək, çünki başlanğıc zirvə öz üzərinə qayıtmağı tələb etməyən ən qısa yol sıfıra bərabərdir. dəyişənində tələb olunan minimal Hamiltonian yolun uzunluğunu saxlayacağıq.
dp[1][0] = 0; total = INF;
for (i = 1; i < n; i++) dp[1 | (1 << i)][i] = dist(0, i);Minimal uzunluqlu Hamiltonian yolu tapırıq. 2n-1 dəyəri \{0, 1, 2, ..., n-1\} çoxluğuna uyğundur. Bütün dəyərlərin ən kiçiyini hesablayırıq:
Minimal Hamiltonian yolun uzunluğunu tapdıqdan sonra nəticəyə sonuncu -ci butulkanın masanın kənarına atılması üçün robotun keçəcəyi məsafə əlavə olunur ki, bu da -yə bərabərdir.
for (i = 1; i < n; i++)
total = min(total, solve((1 << n) - 1, i) + f(i));Nəticə olaraq minimum yolun uzunluğunu çıxarırıq.
printf("%.6lf\n", total);