zoukankan      html  css  js  c++  java
  • [模拟退火][堆优化Prim]2017TG Day2 T2 宝藏

    题目描述

    参与考古挖掘的小明得到了一份藏宝图,藏宝图上标出了 n 个深埋在地下的宝藏屋, 也给出了这 n 个宝藏屋之间可供开发的 m 条道路和它们的长度。

    小明决心亲自前往挖掘所有宝藏屋中的宝藏。但是,每个宝藏屋距离地面都很远,也就是说,从地面打通一条到某个宝藏屋的道路是很困难的,而开发宝藏屋之间的道路 则相对容易很多。

    小明的决心感动了考古挖掘的赞助商,赞助商决定免费赞助他打通一条从地面到某 个宝藏屋的通道,通往哪个宝藏屋则由小明来决定。

    在此基础上,小明还需要考虑如何开凿宝藏屋之间的道路。已经开凿出的道路可以 任意通行不消耗代价。每开凿出一条新道路,小明就会与考古队一起挖掘出由该条道路 所能到达的宝藏屋的宝藏。另外,小明不想开发无用道路,即两个已经被挖掘过的宝藏 屋之间的道路无需再开发。

    新开发一条道路的代价是:

    K

    L代表这条道路的长度,K代表从赞助商帮你打通的宝藏屋到这条道路起点的宝藏屋所经过的 宝藏屋的数量(包括赞助商帮你打通的宝藏屋和这条道路起点的宝藏屋) 。

    请你编写程序为小明选定由赞助商打通的宝藏屋和之后开凿的道路,使得工程总代价最小,并输出这个最小值。

    输入输出格式

    输入格式:

    第一行两个用空格分离的正整数 n,m,代表宝藏屋的个数和道路数。

    接下来 m 行,每行三个用空格分离的正整数,分别是由一条道路连接的两个宝藏屋的编号(编号为 1-n),和这条道路的长度 v

    输出格式:

    一个正整数,表示最小的总代价。

    输入输出样例

    输入样例
    4 5 
    1 2 1 
    1 3 3 
    1 4 1 
    2 3 4 
    3 4 1 
     
    输出样例
    4
    输入样例
    4 5 
    1 2 1 
    1 3 3 
    1 4 1 
    2 3 4 
    3 4 2  
    输出样例
    5

    说明

    【数据规模与约定】

    对于100%的数据:1n12,0m1000,v500000

    分析

    这题用简单的prim算法可以获得45分

    为什么无法拿全分呢?因为prim是类似于贪心的东西,所以最小生成树取到的可能是局部最优解。

    看到局部最优解,会模拟退火的同学嘴角肯定会微微上扬!

    对于prim算法,我们用堆优化,并且以模拟退火得到的概率忽略堆顶元素

    然后就是正常的prim算法了(同时,我们忽略的元素要重新加入堆)

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <queue>
    #include <memory.h>
    using namespace std;
    const int N=1000;
    const int Inf=5e5+1;
    int g[13][13],intr[13],dep[13];
    struct Edge {
        int u,v;
        bool operator <(const Edge a)const {
            return g[u][v]*dep[u]>g[a.u][a.v]*dep[a.u];
        }
    }ntcs[N+10];
    int n,m;
    
    int Prim(int root) {
        priority_queue<Edge> heap;
        int ans=0;
        memset(intr,0,sizeof intr);
        memset(dep,0,sizeof dep);
        dep[root]=1;intr[root]=1;
        while (!heap.empty()) heap.pop();
        for (int i=1;i<=n;i++)
            if (g[root][i]<Inf) heap.push((Edge){root,i});
        for (int j=1;j<n;j++) {
            Edge edge=heap.top();heap.pop();
            int p=0;
            while (!heap.empty()&&(intr[edge.v]||!((int)rand()%n))) {
                if (!intr[edge.v]) ntcs[++p]=edge;
                edge=heap.top();heap.pop();
            }
            intr[edge.v]=1;dep[edge.v]=dep[edge.u]+1;
            for (int i=1;i<=p;i++)
                heap.push(ntcs[i]);
            for (int i=1;i<=n;i++)
                if (g[edge.v][i]<Inf&&!intr[i])
                    heap.push((Edge){edge.v,i});
            ans+=g[edge.u][edge.v]*dep[edge.u];
        }
        return ans;
    }
    
    int main() {
        scanf("%d%d",&n,&m);
        for (int i=1;i<=n;i++)
            for (int j=1;j<=n;j++)
                g[i][j]=Inf;
        for (int i=1;i<=m;i++) {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            g[u][v]=g[v][u]=min(g[u][v],w);
        }
        int ans=2147483647;
        for (int i=1;i<=500;i++)
            for (int j=1;j<=n;j++)
                ans=min(ans,Prim(j));
        printf("%d",ans);
    }
    View Code
    在日渐沉没的世界里,我发现了你。
  • 相关阅读:
    python字符串
    python定义多点坐标_绘制折线_计算起始点和终点
    python进制转化
    python画奥运五环
    python的注释方法行连接符
    python的命名和帮助命令查看关键字
    python的turtle模块画图
    汇编语言
    python自动化办公【第三节 判断语句】
    python自动化办公【第二节 运算及数据类型等【不断修订中】】
  • 原文地址:https://www.cnblogs.com/mastervan/p/9606945.html
Copyright © 2011-2022 走看看