这道题正解是状压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; }