题目链接
题目大意
有n个硬币,每个硬币有一个价值,问你把这些硬币分成两堆,最小的差值是多少
解题思路
其实这个题是个深搜题,但是模拟退火也可以做
随机找两个数交换位置,然后不断更新答案
(模拟退火真是个神奇的玄学算法)
#include<bits/stdc++.h>
using namespace std;
const int N=105;
const double eps=1e-8;
long long a[105],ans;
int n;
long long F()
{
long long ans1=0,ans2=0;
for(int i=1;i<=n;i++)
{
if(i<=(n+1)/2)
ans1+=a[i];
else
ans2+=a[i];
}
return abs(ans1-ans2);
}
void SA()
{
double T=1000000;
while(T>eps)
{
int x=rand()%((n+1)/2)+1,y=rand()%((n+1)/2)+((n+1)/2);
if(x<=0||y<=0||x>n||y>n)
continue;
swap(a[x],a[y]);
long long tmp=F();
if(tmp<ans)
ans=tmp;
else if(exp((double)((double)(ans-tmp)/T)) * RAND_MAX <= rand()) swap(a[x], a[y]);
T*=0.98;
}
}
int main()
{
srand((unsigned)time(NULL));
int T;
scanf("%d",&T);
while(T--)
{
ans=0x3f3f3f3f3f3f3f3f;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
for(int i=1;i<=50;i++)
SA();
printf("%lld\n",ans);
}
return 0;
}