• Bzoj 3680: 吊打XXX (模拟退火)


    Bzoj 3680: 吊打XXX && luogu P1337 [JSOI2004]平衡点 / 吊打XXX (模拟退火)

    Bzoj : https://www.lydsy.com/JudgeOnline/problem.php?id=3680
    luogu : https://www.luogu.org/problemnew/show/P1337
    上午闲来无事,没有比赛可以打....正好洛谷日报更新了模拟退火这篇文章,然后学习了一下,这道题应该是模拟退火的入门经典问题了吧.
    看出来这是一道物理题
    接下来引自attack的博客.
    我们所需要求的点,一定是总能量最小的点,这里的总能量,就是每个点的重力势能之和,如果让一个点的重力势能减小,那么拉它的绳子就应该尽量的长,那么在桌面上的绳子就应该尽量的短
    因此我们需要求得一个点,使得(sum_{i=1}^nd[i]∗w[i])最小 ((d[i])表示该到平衡点的距离,(w[i])表示该点的重量).
    发现这个中间点极值分布的极其不均.
    我们就用模拟退火解决.
    话说求极值的东西都可以用退火搞一下呢.(神奇)

    #include <iostream>
    #include <cmath>
    #include <cstdio>
    #include <cstdlib>
    const int maxN = 10000 + 7;
    const double eps = 1e-16;
    using namespace std;
    
    struct Point {
    	double x,y,w;
    }Map[maxN];
    
    int n;
    
    double Rand(double T) {return T * ( ( rand() << 1 ) - RAND_MAX);}
    
    double calc(double x,double y) {
    	double ans = 0;
    	for(int i = 1;i <= n;++ i) 
    		ans += sqrt( ( x - Map[i].x ) * ( x - Map[i].x ) + ( y - Map[i].y ) * ( y - Map[i].y ) ) * Map[i].w ;
    	return ans;
    }
    
    int main() {
    	srand(20030327);
    	scanf("%d",&n);
    	double Begin_x,Begin_y,Best_ans,Best_x,Best_y;
    	for(int i = 1;i <= n;++ i) {
    		scanf("%lf%lf%lf",&Map[i].x,&Map[i].y,&Map[i].w);
    		Begin_x += Map[i].x;Begin_y += Map[i].y;
    	}
    	Begin_x /= n;Begin_y /= n;
    	Best_ans = calc(Begin_x,Begin_y);
    	Best_x = Begin_x,Best_y = Begin_y;
    	double Delate = 0.98;
    	int Time = 10;
    	while(Time --) {
    		double Now = calc(Begin_x,Begin_y),Now_x = Begin_x,Now_y = Begin_y;
    		for(double T = 1000000;T > eps;T *= Delate) {
    			double tmp_x = Now_x + Rand(T),tmp_y = Now_y + Rand(T);
    			double tmp_ans = calc(tmp_x,tmp_y);
    			if(tmp_ans < Best_ans) {Best_ans = tmp_ans;Best_x = tmp_x;Best_y = tmp_y;}
    			if(tmp_ans < Now || exp( (tmp_ans - Now) / T ) * RAND_MAX < rand()) {
    				Now_x =	tmp_x,Now_y = tmp_y;
    				Now = tmp_ans;
    			}
    		}
    	}
    	printf("%.3lf %.3lf", Best_x, Best_y);
    	return 0;
    }
    
  • 相关阅读:
    非常实用的原创小工具:EasyIP
    ORACLE日期时间函数大全
    Windows 下单机最大TCP连接数
    如何自动以管理员身份运行.NET程序?
    ExecuteScalar 返回值问题
    Assembly类
    .Net字符串驻留池
    进程Process
    C#连接Oracle数据库(直接引用dll使用)
    谈Linux与Windows的比较
  • 原文地址:https://www.cnblogs.com/tpgzy/p/9723417.html
Copyright © 2020-2023  润新知