zoukankan      html  css  js  c++  java
  • 宝藏 题解

    果真是宝藏题目。

    0x01 前置芝士

    这道题我是真没往状压dp上去想。题目来源

    大概看了一下结构。盲猜直接模拟退火!xyx

    所需知识点:模拟退火,贪心。

    0x02 分析

    题目大意:给你一个图,可能有重边,可能有环。让你在这个图上构出一棵树,使得其权值和最小,每条边的权值定义为:这条边的长度 ( imes) 这条边的两个端点中深度小的那一个的深度。输出这个最小权值和。

    于是我们尝试去构造一个序列 (a),然后按照这个序列去构树。

    按照这个序列构出的树保证第 (a[i]) 个结点一定与第 (a[j], j in [1, i - 1]) 个结点相连。

    接下来我们贪心考虑。我们需要使每个点都被拓展到,且权值最小,又因为序列规定,我们需要在已经拓展到的结点去拓展当前结点,那么一定选到当前结点权值最小的已被拓展过的结点进行拓展最优。

    即,如果该树满足 (len(a[i], a[j]) imes dep(a[j]) = mathrm{Min}{len(a[i], a[k]) imes dep(a[k]), k in [1, i - 1]}),其中 (len(x, y)) 表示结点 (x)(y) 边的长度,(dep(x)) 表示结点 (x) 的深度。则此时我们按照这个方式构出的树一定为当前序列下权值和最小的树。

    于是题目转换为找到使得构成的树权值和最小的序列,并得到这个序列对应的最小权值和。

    这样就是裸的模拟退火了。我们以序列 (A,A_i = i) 为初始序列,不断扰动,找到最小值。

    调一下参数,可过。

    srand: 998244353,SA: 7,delta of temperature: 0.996,initial temperature: 1e4,Target temperature: 0.1

    0x03 具体实现

    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    using namespace std;
    
    typedef long long LL;
    int Max(int x, int y) {return x > y ? x : y;}
    int Min(int x, int y) {return x < y ? x : y;}
    int Abs(int x) {return x < 0 ? -x : x;}
    void Swap(int &x, int &y) {int t = x; x = y; y = t;}
    
    int read() {
        int k = 1, x = 0;
        char s = getchar();
        while (s < '0' || s > '9') {
            if (s == '-')
                k = -1;
            s = getchar();
        }
        while (s >= '0' && s <= '9') {
            x = (x << 3) + (x << 1) + s - '0';
            s = getchar();
        }
        return x * k;
    }
    
    void write(int x) {
        if(x < 0) {
        	putchar('-');
    		x = -x;
        }
        if(x > 9)
    		write(x / 10);
        putchar(x % 10 + '0');
    }
    
    void print(int x, char s) {
    	write(x);
    	putchar(s);
    }
    
    const int MAXN = 15;
    const int INF = 0x3f3f3f3f;
    const double q = 0.996;
    int mp[MAXN][MAXN], n;
    int a[MAXN], new_a[MAXN], dep[MAXN];
    
    int f() {
    	dep[new_a[1]] = 1;
    	int res = 0;
    	for(int i = 2; i <= n; i++) {
    		int tmp = INF;
    		for(int j = 1; j < i; j++)
    			if(mp[new_a[j]][new_a[i]] != INF && mp[new_a[j]][new_a[i]] * dep[new_a[j]] < tmp) {
    				tmp = mp[new_a[j]][new_a[i]] * dep[new_a[j]];	
    				dep[new_a[i]] = dep[new_a[j]] + 1;			
    			}
    		if(tmp == INF)
    			return INF;
    		res += tmp;
    	}
    	return res;
    }
    
    void Accept(int now, int &ans) {
    	for(int i = 1; i <= n; i++)
    		a[i] = new_a[i];
    	ans = now;
    }
    
    int SA() {
    	for(int i = 1; i <= n; i++) 
    		a[i] = i;
    	int ans = 0x7f7f7f7f;
    	double t = 1e4;
    	while(t > 0.1) {
    		for(int i = 1; i <= n; i++)
    			new_a[i] = a[i];
    		Swap(new_a[rand() % n + 1], new_a[rand() % n + 1]);
    		int now = f(), delta = now - ans;
    		if(delta < 0) 
    			Accept(now, ans);
    		else if(exp(-delta / t) * RAND_MAX >= rand())
    			Accept(now, ans);
    		t *= q;
    	}
    	return ans;
    }
    
    int main() {
    	srand(998244353);
    	memset(mp, 0x3f, sizeof mp);
    	n = read();
    	int m = read();
    	for(int i = 1; i <= m; i++) {
    		int u = read(), v = read(), w = read();
    		mp[u][v] = Min(mp[u][v], w);
    		mp[v][u] = Min(mp[v][u], w);
    	}	
    	int ans = INF; 
    	for(int i = 1; i <= 7; i++)
    		ans = Min(ans, SA()); 
    	print(ans, '
    ');
    	return 0;
    } 
    
  • 相关阅读:
    Smali基本语法
    图片智能缩小
    How to install ia32-libs in Ubuntu 14.04 LTS (Trusty Tahr)
    [操作系统][Ubuntu 14.04] 安装Flash 安装QQ2013
    eclipse在Ubuntu 13.04下的安装过程及问题小记
    Android系统手机端抓包方法
    Android 开源框架ActionBarSherlock 和 ViewPager 仿网易新闻客户端
    试用Android Annotations
    Android Annotations 介绍
    盘点国内Android移动广告平台的现状
  • 原文地址:https://www.cnblogs.com/Chain-Forward-Star/p/14257684.html
Copyright © 2011-2022 走看看