BZOJ 1013
脑抽了一下,写了个爬山算法找答案。洛谷上一直70分。退火还写残了。(有大佬会退火做法的话,欢迎讨论)
#include<bits/stdc++.h> #define esp 5e-5 #define dla 0.8 #define kkk 1 #define db long double #define random rrr using namespace std; db ask,len[17],sum,f[17][17],ans[17],T,ite,af,dE,a[17],g; int n; inline db check() { //不要问我这个check函数哪里来的,我是一个一个函数试过来的。 ask=0; sum=0; for (int i=1;i<=n+1;i++) { len[i]=0; for (int j=1;j<=n;j++) len[i]=len[i]+(f[i][j]-ans[j])*(f[i][j]-ans[j]); sum=sum+len[i]; } sum=sum/(n+1); for (int i=1;i<=n+1;i++) ask+=(len[i]-sum)*(len[i]-sum); return sqrt(ask); } inline db random() { return 1.0*(rand()%10001)/(10000); } int main () { // freopen("a.in","r",stdin); char*p =new char; srand((unsigned long long)p); scanf("%d",&n); // cerr<<random()<<endl; for (int i=1;i<=n+1;i++) for (int j=1;j<=n;j++) scanf("%Lf",&f[i][j]); T=10000; af=check(); for (int i=1;i<=n;i++) a[i]=i; while (T>esp) { g=5; while (g--) { random_shuffle(a+1,a+n+1); for (int t=1,i;t<=n;t++) { i=a[t]; ans[i]+=T; ite=check();// dE=(-ite+af)*kkk/T; if (ite<af //||exp(dE/T)>random() ) {af=ite;continue;} ans[i]-=2*T; ite=check();// dE=(-ite+af)*kkk/T; if (ite<af //||exp(dE/T)>random() ) {af=ite;continue;} ans[i]+=T; } } T=T*dla; } for (int i=1;i<=n;i++) printf("%.3Lf ",ans[i]); }
然后想到是高斯消元,我们把式子两两相等,就消去了二次项。
#include<bits/stdc++.h> #define db long double #define N 17 using namespace std; db f[N][N],l[N][N]; int n; void init() { scanf("%d",&n); for (int i=0;i<=n;i++) for (int j=1;j<=n;j++) { scanf("%Lf",f[i]+j); if (i) { l[i][j]=2*(f[i][j]-f[i-1][j]); l[i][n+1]+=f[i][j]*f[i][j]-f[i-1][j]*f[i-1][j]; } } } void gao(){ for (int i=1;i<=n;i++) { int t=i; for (int j=i+1;j<=n;j++) if (fabs(l[t][i])<fabs(l[j][i])) t=j; if (t^i) for (int j=1;j<=n+1;j++) swap(l[i][j],l[t][j]); for (int j=i+1;j<=n;j++) { db x=l[j][i]/l[i][i]; for (int k=i;k<=n+1;k++) l[j][k]-=x*l[i][k]; } } for (int i=n;i;i--) { for (int j=i+1;j<=n;j++) l[i][n+1]-=l[i][j]*l[j][n+1]; l[i][n+1]/=l[i][i]; } } int main () { init(); gao(); for (int i=1;i<=n;i++) printf("%.3Lf%c",l[i][n+1],i==n?'\n':' '); }