zoukankan      html  css  js  c++  java
  • [Luogu] 宝藏

    https://www.luogu.org/problemnew/show/P3959

    模拟退火解法

    发现prim求最小生成树是明显错误的

    因为prim每次要取出边权最小的点

    然而在这道T中这样做不一定是最优的

    因此可以随机取出点,这就可能是最优

    当重复次数达到一定次数时,就极有可能成为最优解

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <queue>
    
    using namespace std;
    const int N = 20;
    const int oo = 1e8;
    
    int n, m;
    int dis[N][N], deep[N];
    struct Node {int u, v;};
    Node have_used[N * 100];
    bool vis[N];
    
    bool operator < (const Node a, const Node b) {
        return deep[a.u] * dis[a.u][a.v] > deep[b.u] * dis[b.u][b.v];
    }
    priority_queue <Node> Q;
    
    #define gc getchar()
    
    inline int read() {
        int x = 0; char c = gc;
        while(c < '0' || c > '9') c = gc;
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc;
        return x;
    }
    
    inline int Work(int S) {
        for(int i = 1; i <= n; i ++) deep[i] = 0, vis[i] = 0;
        int last(0), ret(0);
        while(!Q.empty()) Q.pop();
        Node E; deep[S] = 1; vis[S] = 1;
        for(int i = 1; i <= n; i ++) if(dis[S][i] != oo) {E.u = S, E.v = i; Q.push(E);}
        int T = n - 1;
        for(; T; T --) {
            E = Q.top(); Q.pop();
            while(!Q.empty() && (vis[E.v] || rand() % n == 0)) {
                if(!vis[E.v]) have_used[++ last] = E;
                E = Q.top(); Q.pop();
            }
            vis[E.v] = 1;
            deep[E.v] = deep[E.u] + 1;
            for(; last; last --) Q.push(have_used[last]);
            last = 0;
            ret += deep[E.u] * dis[E.u][E.v];
            Node E2;
            for(int i = 1; i <= n; i ++) {
                if((dis[E.v][i] != oo) && !vis[i]) {E2.v = i; E2.u = E.v;Q.push(E2);}
            }
        }
        return ret;
    }
    
    int main() {
        srand(20001206);
        n = read(); m = read();
        for(int i = 1; i <= n; i ++) for(int j = 1; j <= n; j ++) dis[i][j] = oo;
        for(int i = 1; i <= m; i ++) {
            int a = read(), b = read(), c = read();
            dis[a][b] = dis[b][a] = min(dis[a][b], c); 
        }
        int Answer = oo, T = 1000;
        for(; T; T --) 
            for(int i = 1; i <= n; i ++) Answer = min(Answer, Work(i));
        cout << Answer; 
        return 0;
    }
  • 相关阅读:
    Promise
    includes()
    常见的数组去重方法
    concat()
    面试感想
    常见的前端面试题
    让div水平垂直居中的几种方法
    实现斐波拉契的几种方法
    使用lib-flexible
    什么是token
  • 原文地址:https://www.cnblogs.com/shandongs1/p/8986417.html
Copyright © 2011-2022 走看看