zoukankan      html  css  js  c++  java
  • [NOIP2017 提高组] 宝藏

    考虑到这种对于某种操作顺序有一个权值。
    且这个权值有一个\(O(n)\)或者更好的复杂度求出。
    求最值。
    那可以用模拟退火。

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<ctime>
    #include<cmath>
    #define ll long long
    #define N 20
    
    ll n,m;
    
    ll f[N][N];
    
    ll in[N],dis[N];
    
    inline ll find(){
    	ll ans = 0;
    	for(int i = 1;i <= n;++i)
    	dis[i] = 0;
    	for(int i = 2;i <= n;++i){
    		ll lim = 1e18;
    		for(int j = 1;j <= i - 1;++j){
    			if(lim > ((dis[in[j]] + 1) * f[in[j]][in[i]]))
    			lim = ((dis[in[j]] + 1) * f[in[j]][in[i]]),dis[in[i]] = dis[in[j]] + 1;
    		}
    		ans = ans + lim;
    	}
    	return ans;
    }
    
    ll fans = 1e18;
    
    inline void sa(){
    	double T = 20000;
    	double eps = 1e-15;
    	while(T > eps){
    		ll z = -find();
    		int x,y;
    		x = rand() % n + 1;
    		y = rand() % n + 1;
    		fans = std::min(fans,-z);
    		std::swap(in[x],in[y]);
    		z = z + find();
    		if(z > 0 && exp(-z / T) * RAND_MAX < rand())
    		std::swap(in[x],in[y]);
    		T *= 0.996;
    	}
    }
    
    int main(){
    	scanf("%lld%lld",&n,&m);
    	for(int i = 1;i <= N;++i)
    	for(int j = 1;j <= N;++j)
    	f[i][j] = 1e18;
    	for(int i = 1;i <= m;++i){
    		ll x,y,z;
    		scanf("%lld%lld%lld",&x,&y,&z);
    		f[x][y] = std::min(z,f[x][y]);
    		f[y][x] = std::min(z,f[y][x]);
    	}
    	for(int i = 1;i <= n;++i)
    	in[i] = i;
    	fans = find();
    	while(((double)(clock())/CLOCKS_PER_SEC)<0.5)
    	sa();
    	std::cout<<fans<<std::endl;
    }
    
    
  • 相关阅读:
    Day5下午解题报告1
    Linux 命令整理
    [置顶] 正则表达式应用:匹配email地址
    IE浏览器下web调试工具之--IE WebDeveloper介绍
    ORACLE客户端乱码
    冒泡排序
    【C++】第二章:Hello World!
    hdu4710
    (SQL SERVER) (ORACLE) (ACCESS)(POSTGRE SQL)四种数据库操作C#代码
    How to calculate the undo_retention time
  • 原文地址:https://www.cnblogs.com/dixiao/p/15099327.html
Copyright © 2011-2022 走看看