NOIP2017 宝藏
模拟退火这个算法最大的难点在调参-_-!
又是本机AC提交WA系列。。。
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; double rand_d(){return double(rand()%10000)/10000.0;} int n,m,p[20];LL ans; int mp[20][20]; bool o[20][20];void oc(int x,int y){o[x][y]^=1,o[y][x]^=1;} //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ int prd[20],prr[20];bool prv[20]; void prim() { memset(prd,63,sizeof(prd)); memset(prv,false,sizeof(prv)); for(int i=1;i<n;i++) { int x=0; for(int j=1;j<=n;j++) if(prv[j]==false&&(x==0||prd[x]>prd[j]))x=j; prv[x]=1; for(int y=1;y<=n;y++) if(prv[y]==false) { if(mp[x][y]<prd[y]) prd[y]=mp[x][y], prr[y]=x; } } memset(o,false,sizeof(o)); for(int i=2;i<=n;i++) p[i-1]=i*20+prr[i],o[i][prr[i]]=o[prr[i]][i]=true; } //----------------------------------init--------------------------------------------------- LL sum; void calc_dfs(int x,int fr,int dep) { for(int y=1;y<=n;y++) if(o[x][y]&&y!=fr) { sum+=(LL)mp[x][y]*(LL)dep; calc_dfs(y,x,dep+1); } } LL calc() { LL mmin=(1LL<<62); for(int i=1;i<=n;i++) { sum=0,calc_dfs(i,0,1); mmin=min(sum,mmin); } ans=min(ans,mmin); return mmin; } //-------------------------------calc---------------------------------------------------- int c1[20],c2[20];bool cc[20]; void gocolor(int x,int fr) { cc[x]=true;c1[++c1[0]]=x; for(int y=1;y<=n;y++) if(o[x][y]&&y!=fr) if(cc[y]==false)gocolor(y,x); } void annealing() { int T=1000000; while(T>0.01) { LL pd=calc(); int id=rand()%(n-1)+1; int px=p[id]/20,py=p[id]%20; oc(px,py); c1[0]=0,c2[0]=0; memset(cc,false,sizeof(cc)); gocolor(1,0); for(int i=1;i<=n;i++) if(cc[i]==false)c2[++c2[0]]=i; int nx=c1[rand()%c1[0]+1],ny=c2[rand()%c2[0]+1]; oc(nx,ny); LL nd=calc(); if(pd>nd||exp((pd-nd)/T)>rand_d())p[id]=nx*20+ny; else oc(px,py),oc(nx,ny); T*=0.9999; } for(int i=1;i<=1000;i++) { LL pd=calc(); int id=rand()%(n-1)+1; int px=p[id]/20,py=p[id]%20; oc(px,py); c1[0]=0,c2[0]=0; memset(cc,false,sizeof(cc)); gocolor(1,0); for(int i=1;i<=n;i++) if(cc[i]==false)c2[++c2[0]]=i; int nx=c1[rand()%c1[0]+1],ny=c2[rand()%c2[0]+1]; oc(nx,ny); LL nd=calc(); oc(px,py),oc(nx,ny); } } //---------------------------annealing---------------------------------------------------- int main() { srand(456456); int x,y,dd; scanf("%d%d",&n,&m); if(n==1){printf("0\n");return 0;} memset(mp,63,sizeof(mp)); for(int i=1;i<=m;i++) { scanf("%d%d%d",&x,&y,&dd); mp[x][y]=mp[y][x]=min(mp[x][y],dd); } prim(),ans=calc(); annealing(); printf("%lld\n",ans); return 0; }
pain and happy in the cruel world.