給定n個大小不等的圓c1,c2,…,cn,現要將這n個圓排進乙個矩形框中,且要求各圓與矩形框的底邊相切。圓排列問題要求從n個圓的所有排列中找出有最小長度的圓排列。例如,當n=3,且所給的3個圓的半徑分別為1,1,2時,這3個圓的最小長度的圓排列如圖所示。其最小長度為。
圓排列問題的解空間是一棵排列樹,按照回溯法搜尋排列數的演算法框架
設所有圓的半徑為 a = [r1 , r2 , r3 … , rn];
那麼對應的排列數有 a[1 : n ]的全排列構成
那麼我們通過回溯法計算最優圓排列的時候需要注意幾個問題
(1)首先是相切問題:
如圖:
在思考本題是很容易先入為主的認為,相鄰的圓是相切的,但是實際上通過這個圖我們可以知道,最後乙個圓是有可能和它之前的任意乙個圓相切的,如果以相鄰圓相切的思路做題,得出的結果有可能會偏小
(2)其次是剪枝問題:
在圓排列問題中我們需要構造全排列,通過排列組合可以知道構造全排列的時間複雜度為o(n!),但是實際上有一些圓排列在僅有一部份圓的時候其長度就已經超過了最小長度,因此有這些部分圓排列所演變出的圓排列明顯是不符合的。
這可以在某些情況下減少演算法的時間複雜度。
計算當前圓的橫座標
1通過回溯法夠成圓排列的全排列,因為用於記錄圓橫座標的x陣列,定義為了全域性變數,因此第乙個圓的橫座標被預設設定為了0,在計算圓排列長度進行剪枝的時候需要加上第乙個圓的半徑。double get_center(intt)2
9return
tmp;
10 }
1由排列組合可知,生成乙個長度為n的序列的全排列的時間複雜度為o(n!)同時在這個演算法中,對於每乙個排列中的每乙個圓,它有可能和在它之前的任意乙個圓相切,為了正確的確定是與那個圓相切需要使用for迴圈進行遍歷,通過遍歷找到與之相切的圓,其每次的時間複雜度為o(n)綜上所述,計算最小圓排列的複雜度為o(n * n!)void dfs(int
pos)27
else
818 swap(r[pos], r[i]); //
構造全排列19}
20}21 }
1 #include2 #include3 #include4完整**using
namespace
std;56
7const
int maxn = 1e5 + 10;8
double minlen =1e5;
9double
x[maxn], r[maxn];
10//
x儲存每個圓心的橫座標 , r儲存每個圓的半徑 ,
11//
由於x陣列為全域性變數,因此初始化為0,因此第乙個圓的橫座標預設為0,因此在計算最小圓排列長度的時候還需要注意加上第乙個圓的半徑
12double bestr[maxn]; //
儲存最優的圓排列的半徑順序
13int
n;14
15double get_center(int
t)16
23return
tmp;24}
2526
void
get_ans()
2734
if (maxx - minn
3541}42
}434445
void dfs(int
pos)
4651
else
5262 swap(r[pos], r[i]); //
構造全排列63}
64}65}
6667
68int
main()
6977
for (int i = 1; i <= n; ++i)
7881 dfs(1
);82 cout << "
最小圓排列的長度為:
"<< minlen <
83 cout << "
最優原排列的順序對應的半徑分別為:";
84for (int i = 1; i <= n; ++i)
8588 cout <
89return0;
90 }
演算法大作業 圓排列問題
圓排列問題 給定n個圓的半徑序列,將它們放到矩形框中,各圓與矩形底邊相切,求具有最小排列長度的圓排列。首先舉乙個例子,當給定的圓半徑為1,1,3時則可以給出如下排列使排列長度最小 所以這題也算是乙個排列問題,如何排列能夠使排列的長度最小。在排列時有以下幾種情況 1 每個圓相繼相切 如上面的例子裡每個...
大作業(圓排列問題)
圓排列問題 給定n個圓的半徑序列,將它們放到矩形框中,各圓與矩形底邊相切,求具有最小排列長度的圓排列。圓排列問題的解空間是一棵排列樹,按照回溯法搜尋排列數的演算法框架 設所有圓的半徑為 a r1 r2 r3 rn 那麼對應的排列數有 a 1 n 的全排列構成。並且只要大小合適,目標圓就有可能與排列中...
演算法分析期末大作業 回溯演算法 圓排列問題
第乙個圓的圓心橫座標為0 定義x k 陣列算出排列第k個圓的圓心橫座標 minlen為最短的矩形的長度if centerx r t r 1 求圓心橫座標 double center int t return temp 排列第乙個的圓的圓心橫座標是0 回溯演算法 void backtrack int ...