P2210 Haywire 【模拟退火】
洛谷 P2210 -> Click Here
题意
有 \(N\) 头 (\(4\leq N\leq 12\)) 奶牛,每头奶牛有且只有 \(3\) 个朋友,如果奶牛 \(A\) 是奶牛 \(B\) 的朋友,那么奶牛 \(B\) 也是奶牛 \(A\) 的朋友,将这些奶牛排列在整数轴上,两只奶牛的距离为两只奶牛之间的间隔的整数的个数,任意排列奶牛,求所有奶牛的朋友间的距离最小距离
思路
与P3837 分硬币类似,都是对整数列进行随机交换两个数字,逐渐降温,求最小值,详情左转 -> P3878 分金币 模拟退火题解
本题对奶牛的顺序进行随机化,交换两个奶牛的位置,查看是否更优或在一定接受的概率内逐渐降温,最后找到最小值
code
#include<iostream>
#include<cstdlib>
#include<ctime>
#include<vector>
#include<cmath>
#include<algorithm>
#define REP(i,a,b) for(int i=(a);i<=(b);i++)
#define FOR(i,a,b) for(int i=(a);i<(b);i++)
using namespace std;
typedef long long ll;
ll n;
// int plac[15];
int fir[22][22];
int ans=99999999;
vector<int> v[22];
vector<int> plac(22),ansv;
int get(){
int res=0;
REP(i,1,n) FOR(j,0,3) res+=abs(plac[v[i][j]]-plac[i]);
return res;
}
void SA(){
double T=10000,down=0.996,eT=1e-15;
while(T>eT){
int x=rand()%n+1,y=rand()%n+1;
swap(plac[x],plac[y]);
int nowans=get();
int del=nowans-ans;
if(del<0) ans=nowans;
else{
if(exp(- del/T)*RAND_MAX>rand())
swap(plac[x],plac[y]);
}
T*=down;
}
}
void solve(){
srand(time(0));
cin>>n;
REP(i,1,n){
plac[i]=i;
int a,b,c;
cin>>a>>b>>c;
v[i].push_back(a);
v[i].push_back(b);
v[i].push_back(c);
}
int cnt=250;
while(cnt--) SA();
cout<<ans/2<<endl;
}
int main(){solve();return 0;}

浙公网安备 33010602011771号