• Luogu P3959 宝藏


    这道题正解是状压DP,不过我不会所以写一下随机化算法来骗骗分。

    听说当时考场上就有很多写prim然后挂掉的神仙,其实这道题是可以prim过的

    prim是一种基于贪心的算法,在本题中由于盲目的选择当前最优解可能会使得后面的决策不优,于是我们请出基于随机化的prim我口胡的

    每一次选择边的时候,有概率的跳过一些对于当前来说最优的边,这样为后面可能跑出更优的解做出铺垫。

    这样一次可能得到的解还不如直接贪心得到的解优,但是我复杂度这么小,跑个几千次又怎样?

    然后选好随机数种子,满怀信仰地祈祷就可以AC了

    虽然这不是严格意义上的模拟退火,但是随机化的思想还是比较神仙的

    CODE

    #include<cstdio>
    #include<cctype>
    #include<cstdlib>
    #include<cstring>
    #include<queue>
    #include<ctime>
    using namespace std;
    const int N=15,M=1005;
    int edge[N][N],n,m,x,y,z,dep[N],ans,INF;
    bool vis[N];
    struct data
    {
        int fr,to;
        bool operator <(const data a) const { return dep[a.fr]*edge[a.fr][a.to]<dep[fr]*edge[fr][to]; }
    }stack[M];
    priority_queue <data> small;
    inline char tc(void)
    {
        static char fl[100000],*A=fl,*B=fl;
        return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
    }
    inline void read(int &x)
    {
        x=0; char ch; while (!isdigit(ch=tc()));
        while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc()));
    }
    inline int Simulate_Anneal(int st)
    {
        memset(dep,0,sizeof(dep)); memset(vis,0,sizeof(vis)); 
        register int i; int tot=0,top=0; memset(stack,0,sizeof(stack));
        while (!small.empty()) small.pop(); dep[st]=vis[st]=1;
        for (i=1;i<=n;++i) if (edge[st][i]<INF) small.push((data){st,i});
        for (i=1;i<n;++i)
        {
            data e=small.top(); small.pop();
            while (!small.empty()&&(vis[e.to]||!(rand()%n)))
            {
                if (!vis[e.to]) stack[++top]=e;
                e=small.top(); small.pop();
            }
            vis[e.to]=1; dep[e.to]=dep[e.fr]+1; tot+=dep[e.fr]*edge[e.fr][e.to];
            while (top) small.push(stack[top--]);
            for (register int j=1;j<=n;++j)
            if (!vis[j]&&edge[e.to][j]<INF) small.push((data){e.to,j});
        }
        return tot;
    }
    inline void miner(int &x,int y)
    {
        x=y<x?y:x;
    }
    int main()
    {
        //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
        register int i,t=200; read(n); read(m); srand(20030909);
        memset(edge,63,sizeof(edge)); ans=INF=edge[0][0];
        for (i=1;i<=m;++i)
        {
            read(x); read(y); read(z);
            miner(edge[x][y],z); miner(edge[y][x],z);
        }
        while (t--)
        for (i=1;i<=n;++i)
        miner(ans,Simulate_Anneal(i));
        return printf("%d",ans),0;
    }
    
  • 相关阅读:
    每天一个linux命令(6):mv命令
    每天一个linux命令(5):rm 命令
    每天一个linux命令(4):mkdir命令
    每天一个linux命令(3):pwd命令
    每天一个linux命令(2):cd命令
    每天一个linux命令(1):ls命令
    Linux下svn命令详解
    Linux下SVN安装配置
    SVN命令使用详解
    分布式Web服务器架构
  • 原文地址:https://www.cnblogs.com/cjjsb/p/9513558.html
Copyright © 2020-2023  润新知