题解 P1216 【[USACO1.5]数字三角形 Number Triangles】
看了洛谷日报的模拟退火算法,传送门,决定用一道简单题目练练手,具体算法的讲解文章已经非常详细。 结果错了最后3个点,因为解空间不连续,数据大的时候容易陷入局部最优解,不容易跳出来。但也是一种方法,对于理解模拟退火还是很有帮助的。
#include <bits/stdc++.h>
#define re register
using namespace std;
int a[1010][1010];
int n,tt;
bool sx[1010];//搜索顺序,0代表选下面更大的数字,1选更小的,初始值全是0,就变成贪心,从贪心的结果出发
double ans,t; //全局最优解、温度
const double delta=0.997; //降温系数
void input() {
scanf("%d",&n);
for (int i=1; i<=n; i++)
for (int j=1; j<=i; j++)
scanf("%d",&a[i][j]);
}
//计算和
int jisuan() {
int tmpans=a[1][1],x=1,y=1;
for (re int i=1; i<n; i++) {
if (sx[i]) {
if (a[x+1][y]<a[x+1][y+1])
tmpans+=a[x+1][y],++x;
else
tmpans+=a[x+1][y+1],++x,++y;
} else {
if (a[x+1][y]>a[x+1][y+1])
tmpans+=a[x+1][y],++x;
else
tmpans+=a[x+1][y+1],++x,++y;
}
}
return tmpans;
}
inline void simulate_anneal() { //SA主过程
t=2000; //初始温度
while (t>1e-14) {
srand(rand());
int w=rand()%(n)+1; //随机更改其中一个方向
sx[w]^=true;
int now=jisuan();
int Delta=now-ans;
if (Delta>0) { //接受
ans=now;
} else if (exp(-Delta/t)*RAND_MAX<rand()) sx[w]^=true; //以一个概率接受
t*=delta;
}
}
int main() {
srand(125897);
srand(rand());
srand(rand()); //玄学srand
input();
ans=jisuan();
simulate_anneal();
simulate_anneal();
cout<<ans<<endl;
return 0;
}