模拟退火算法解决最近最远问题

/**
    模拟退火算法真的很巧妙,而且很多问题也能转换成这个算法
    这个算法最大的妙处,就是它会无序的向着你所要求的答案去
    寻找,直到找到符合你的精度,概率很高

    如:在一个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
来自于百度空间

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值