小结:
主要是能够把rand的方式弄清:
①点的随机化:直接rand。
②序列的随机化:rand两个位置交换或rand整个序列。
③树的随机化:尽量把其转成序列形式,同序列rand即可。
接下来只要知道怎样算答案,剩下的基本上就是上板子,注意调参的问题就好了。
一般以exp(-△ans/T)*RAND_MAX>rand()为条件接受较劣解,注意需保证exp内的值恒为负数。
上几道题。
点的随机,直接rand就好了。
然后答案的计算,ans=∑(dis*w[i]);

#include<bits/stdc++.h> #define RG register #define IL inline #define DB double #define LL long long using namespace std; IL int gi() { RG int x=0,w=0; char ch=0; while (ch<'0'||ch>'9') {if (ch=='-') w=1;ch=getchar();} while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar(); return w?-x:x; } const int N=1e3+10; const DB dT=0.99; const DB eps=1e-14; int n; DB x,y,ans=1e18+0.1; struct Object{DB x,y,w;}ob[N]; IL DB Rand() {return (DB)(rand()*rand()-RAND_MAX);} IL DB get_sum(DB x,DB y) { RG int i; RG DB sum=0; for (i=1;i<=n;++i) sum+=sqrt((ob[i].x-x)*(ob[i].x-x)+(ob[i].y-y)*(ob[i].y-y))*ob[i].w; return sum; } IL void SA() { RG DB ax=x,ay=y,nowx,nowy,Nans; RG DB T=70000,Dans; while (T>=eps) { nowx=ax+Rand()*T,nowy=ay+Rand()*T; Nans=get_sum(nowx,nowy); Dans=Nans-ans; if (Dans<0) ans=Nans,ax=x=nowx,ay=y=nowy; else if (exp(-Dans/T)*RAND_MAX>rand()) ax=nowx,ay=nowy; T*=dT; } } int main () { RG int i; for (i=1,n=gi();i<=n;++i) scanf("%lf%lf%lf",&ob[i].x,&ob[i].y,&ob[i].w); srand(time(0)),SA(); printf("%lf %lf ",x,y); return 0; }
二、均分数据
序列的随机,rand两个位置交换。
答案统计用动态规划:
f[i][j]=f[i][j]=min{f[k][j-1]+(pre[i]-pre[k]-ave)*(pre[i]-pre[k]-ave)};
刚做这个题时,too naive。。。交了20多发。
发现只模拟退火一次总会错一点。后面发现,初始温度设低一点,多跑几次正确率高些。

#include<bits/stdc++.h> #define RG register #define IL inline #define DB double #define LL long long using namespace std; IL int gi() { RG int x=0,w=0; char ch=0; while (ch<'0'||ch>'9') {if (ch=='-') w=1;ch=getchar();} while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar(); return w?-x:x; } const int N=21; const DB dT=0.99; const DB eps=1e-10; DB ave,Ans=1e18,pre[N],f[N][N]; int n,m,a[N]; IL DB Work() { RG int i,j,k; memset(f,127,sizeof(f)); memset(pre,0,sizeof(pre)); f[0][0]=0; for (i=1;i<=n;++i) pre[i]=pre[i-1]+a[i]; for (i=1;i<=n;++i) for (j=1;j<=i&&j<=m;++j) for (k=0;k<i;++k) f[i][j]=min(f[i][j],f[k][j-1]+(pre[i]-pre[k]-ave)*(pre[i]-pre[k]-ave)); return f[n][m]; } void simulate_A() { RG DB T=6666,ans; RG int nx,ny; while (T>=eps) { if (Ans==0) break; nx=rand()%n+1,ny=rand()%n+1; while (nx==ny) nx=rand()%n+1,ny=rand()%n+1; swap(a[nx],a[ny]); ans=Work(); if (ans<Ans) Ans=ans; else if (exp((Ans-ans)/T)*RAND_MAX<=rand()) swap(a[nx],a[ny]); T*=dT; } } int main () { srand(19260817); RG int i; n=gi(),m=gi(); for (i=1;i<=n;++i) a[i]=gi(),ave+=a[i]; ave=ave/(DB)m,Ans=Work(); for (i=1;i<=66;++i) simulate_A(); printf("%.2lf ",sqrt(Ans/(DB)m)); return 0; }
三、分金币
序列的随机,rand两个位置交换。
答案统计,直接从前往后扫一遍,前后两半的差作为结果。

#include<bits/stdc++.h> #define RG register #define IL inline #define DB double #define LL long long using namespace std; IL int gi() { RG int x=0,w=0; char ch=0; while (ch<'0'||ch>'9') {if (ch=='-') w=1;ch=getchar();} while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar(); return w?-x:x; } const int N=51; const int INF=0x3f3f3f3f; const DB dT=0.99; const DB eps=1e-10; int n,ans,a[N]; IL int Work() { RG int i,sum1=0,sum2=0; for (i=1;i<=n;++i) if (i<=(n+1>>1)) sum1+=a[i]; else sum2+=a[i]; return abs(sum1-sum2); } void simulate_A() { RG DB T=5000; RG int x,y,Minx; while (T>=eps) { x=rand()%(n+1>>1)+1,y=rand()%(n>>1)+(n+1>>1)+1; swap(a[x],a[y]); Minx=Work(); if (Minx<ans) ans=Minx; else if (exp((DB)(ans-Minx)*1.0/T)*RAND_MAX<=rand()) swap(a[x],a[y]); T*=dT; } } int main () { srand(time(0)); RG int i,T=gi(); while (T--) { n=gi(),ans=INF; for (i=1;i<=n;++i) a[i]=gi(); if (n==1) {printf("%d ",a[1]);continue;} for (i=1;i<=20;++i) simulate_A(); printf("%d ",ans); } return 0; }
四、Haywire
基本一样。。。好像没什么可讲了。。。

#include<bits/stdc++.h> #define RG register #define IL inline #define DB double #define LL long long using namespace std; IL int gi() { RG int x=0,w=0; char ch=0; while (ch<'0'||ch>'9') {if (ch=='-') w=1;ch=getchar();} while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar(); return w?-x:x; } const int N=13; const DB dT=0.99; const DB eps=1e-10; int n,ans,a[N][N],P[N]; IL int Rand(int x) {return rand()%n+1;} IL int calc() { RG int i,j,cnt=0; for (i=1;i<=n;++i) for (j=i+1;j<=n;++j) if (a[i][j]) cnt+=abs(P[i]-P[j]); return cnt; } IL void simulate_A() { RG DB T=6666; RG int x,y,now; while (T>=eps) { x=Rand(n),y=Rand(n); while (x==y) x=Rand(n),y=Rand(n); swap(P[x],P[y]); now=calc(); if (now<ans) ans=now; else if (exp((ans-now)/T)*RAND_MAX<=rand()) swap(P[x],P[y]); T*=dT; } } int main () { srand(time(0)); RG int i,j,x; for (i=1,n=gi();i<=n;++i) for (j=1;j<=3;++j) x=gi(),a[i][x]=a[x][i]=1; for (i=1;i<=n;++i) P[i]=i; ans=calc(); for (i=1;i<=20;++i) simulate_A(); printf("%d ",ans); return 0; }
五、宝藏
这里用模拟退火来做。
这是树上问题。怎么来随机呢?
我们还是尽量把它转成序列来做:
不妨把每一个节点先扔在一个序列中,然后考虑这棵树的生成。
我们可以按照序列的顺序,依次把节点加入树中,
贪心的来选择当前节点与之前哪个节点连边。
如果发现当前序列下,无法生成一棵树,那么就退出。
这样的话,我们就可以按照序列的随机那样,rand两个节点交换就好了。
统计答案的话,就是在生成树的过程中,一起计算了。

#include<bits/stdc++.h> #define RG register #define IL inline #define DB double #define LL long long using namespace std; IL int gi() { RG int x=0,w=0; char ch=0; while (ch<'0'||ch>'9') {if (ch=='-') w=1;ch=getchar();} while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar(); return w?-x:x; } const int N=15; const int INF=0x3f3f3f3f; const DB dT=0.99; const DB eps=1e-10; int n,m,ans,P[N],ver[N][N],dep[N]; IL int solve() { RG int i,j,cost,Ans=0; dep[P[1]]=1; for (i=2;i<=n;++i) { for (j=1,cost=INF;j<i;++j) if (ver[P[i]][P[j]]&&dep[P[j]]*ver[P[i]][P[j]]<cost) cost=dep[P[j]]*ver[P[i]][P[j]],dep[P[i]]=dep[P[j]]+1; if (cost==INF) return INF; Ans+=cost; } return Ans; } IL void simulate_A() { RG DB T=8888; RG int x,y,now; while (T>=eps) { x=rand()%n+1,y=rand()%n+1; while (x==y) x=rand()%n+1,y=rand()%n+1; swap(P[x],P[y]),now=solve(); if (now<ans) ans=now; else if (exp((ans-now)/T)*RAND_MAX<=rand()) swap(P[x],P[y]); T*=dT; } } int main () { srand(time(0)); RG int i,x,y,z; n=gi(),m=gi(); if (m==0) {puts("0");return 0;} for (i=1;i<=m;++i) { x=gi(),y=gi(),z=gi(); if (x==y) continue; if (z<ver[x][y]||!ver[x][y]) ver[x][y]=ver[y][x]=z; } for (i=1;i<=n;++i) P[i]=i; ans=solve(); for (i=1;i<=66;++i) simulate_A(); printf("%d ",ans); return 0; }