洛谷 P2210 Haywire 題解報告
阿新 • • 發佈:2021-11-28
題目連結
如果不瞭解退火,可以先右轉去這篇文章 模擬退役
註釋都寫在了程式碼裡,這裡不過多贅述,上程式碼
點選檢視程式碼
#include<bits/stdc++.h> #define d 0.996 #define lim 1e-10//停止溫度 #define INF 0x3f3f3f3f using namespace std; int n; int ans=INF; int del,now,nowx,nowy; int so[18],su[18][18]; int calc() { int res=0; for(int i=1;i<=n;i++) for(int j=1;j<=3;j++) res+=abs(so[i]-so[su[i][j]]);//n<=12 直接暴力列舉,每個奶牛的位置差 res=res>>1;//每個奶牛的位置都算了兩遍,需要除以2 return res; } void sa() { double T=2021;//溫度可設在1999~2021,更容易跑到最優解 while(T>lim) { // nowx=rand()%n+1; // nowy=rand()%n+1; // swap(so[nowx],so[nowy]);產生兩個種子,隨機交換這兩點的位置 random_shuffle(so+1,so+n+1);//此題在退火最少次數內隨機打亂序列比隨機交換正確率高 now=calc(); del=now-ans;//溫度差 if(del<0) ans=now;//如果溫差小於0,說明此時新產生的答案now比ans更優 else if(exp(-del/T)<(double)rand()/RAND_MAX){//否則以一定概率接受此解(一定要寫,不寫會錯,當板子背過就好了) } T*=d;//降溫 } } void work() { for(int i=1;i<=12;i++) sa();//測了11次,此題可以把退火次數壓縮到12(退火次數越多得到正確答案几率越大,但要注意時間複雜度 } int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } int main() { n=read(); for(int i=1;i<=n;i++) { su[i][1]=read();//二維陣列記錄朋友位置 su[i][2]=read(); su[i][3]=read(); so[i]=i;//記錄自己的位置 } work(); printf("%d",ans); return 0; }