Luogu P3959 宝藏

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

据说当时考场上就有不少写prim而后挂掉的神仙,其实这道题是能够prim过的算法

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

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

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

而后选好随机数种子,满怀信仰地祈祷就能够AC了it

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

CODEclass

#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;
}
相关文章
相关标签/搜索