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;
}
相關文章
相關標籤/搜索