/**
模拟退火算法真的很巧妙,而且很多问题也能转换成这个算法
这个算法最大的妙处,就是它会无序的向着你所要求的答案去
寻找,直到找到符合你的精度,概率很高
如:在一个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
来自于百度空间
模拟退火算法解决最近最远问题
最新推荐文章于 2021-07-27 15:52:14 发布