/**
模擬退火算法真的很巧妙,而且很多問題也能轉換成這個算法
這個算法最大的妙處,就是它會無序的向着你所要求的答案去
尋找,直到找到符合你的精度,概率很高
如:在一個1024*768的平面上有N 個點,現在要你在這個面上找個
點到這N個點的距離和最小,精度保留 5 位小數,有個很簡單的辦法
就是枚舉,當然不能這麼幹,而模擬退火算法是處理這類問題的典範
當然它不僅僅用於處理找點,你知道,網絡流就是求最大流而已,可是
卻用處很多,所以說好多問題,都可一轉換成模擬退火問題,尤其那些
沒有確定算法,需要暴力的題,包括今年上海賽區第一題也是可以用這個
算法,不過會超時。
接着回到那個題,找一個點到這些點距離最小,模擬退火的思路就是,先任意
在這個面內找個點 st ,最好在這些點中間,設有個半徑爲 T,以T爲半徑
st 爲圓心可以包括所有的N 個點。好了,下面開始找了,一般 8 個方向就夠了
4個其實也差不多,對於有些題要求很高,需要更多的方向,現在就以4 個
方向分析,上下左右,st點的上下左右,st_up, st_down, st_left, st_right.
比如:st_up.x = st.x, st_up.y = st.y + T。 在這四個點裏面挑個離得最近的
把st 移到這裏,然後繼續找直到T 的半徑下再也找不到更近的點,現在T *= 0.5
繼續重複上面步驟找,要知道,每次讓T 減一般,很快就會減到你想要的精度。
具體看代碼
*/
typedef struct POINT {
double x, y;
}Point;
int main() {
Point st, st_tmp, temp; //st_tmp, temp臨時點
double T, T_MIN; // T要求把所有點覆蓋,T_MIN可得到的最大精度 比如 T_MIN = 1e-6
double ans; //目前可得的最小距離
//輸入完成後
st_tmp = st;
ans = dis(st); //dis() 函數由自己寫,返回st 離所有點的距離之和
while (T > T_MIN) {
int flag;
while (flag) {
flag = 0; //flag 的妙處
for (int i=-1; i<=1; i++)
for (int j=-1; j<=1; j++) { //八個方向,根據需要自己看着辦
temp.x = st.x + T*i;
temp.y = st.y + T*j;
double tmp_d = dis(temp);
if (tmp_d < ans) {
ans = tmp_d;
st_tmp = temp;
flag = 1; //在T 半徑上找到個比st 更小的點
}
}
st = st_tmp; //如果flag = 0,說明在T 半徑的8個方向上沒有比st 更優的點
}
T = 0.5 * T; //這個也是根據情況,不過一般0.5就行了,越大越精確,速度也越慢
}
// 得到 st 爲最近點,ans 爲最近距離和,最遠一樣,改改即可
return 0;
}
/**
睡覺了,睡覺了,晚安
*/
收藏於 2012-01-13
來自於百度空間
模擬退火算法解決最近最遠問題
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.