P3878 [TJOI2010]分金币

题目链接

题意分析

这道题正解好像是折半状压 但是俺就是喜欢模拟退火

每一次随机的话 就是交换两个数的位置 然后比较前一半和后一半

CODE:

#include<bits/stdc++.h>
#define INF 0x7fffffff
#define N 2010
using namespace std;
int T,n;
long long ans;
long long num[N];
long long getans()
{
	long long sum1=0,sum2=0;
	int mid=(1+n)>>1;
	for(int i=1;i<=mid;++i) sum1+=num[i];
	for(int i=mid+1;i<=n;++i) sum2+=num[i];
	return abs(sum1-sum2);
}
void SA()
{
	for(double Te=3872;Te>1e-10;Te*=0.972)
	{
		int x=rand()%n+1,y=rand()%n+1;
		swap(num[x],num[y]);
		long long tmp=getans();
		if(tmp<ans) ans=tmp;
		else if(exp((double)(ans-tmp)/Te)*RAND_MAX<(double)rand()) swap(num[x],num[y]); 
	}
}
int main()
{
	srand(19260817+998244353);
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d",&n);
		for(int i=1;i<=n;++i) scanf("%lld",&num[i]);
		ans=INF;
		for(int x=1;x<=1000;++x) SA();
		printf("%lld\n",ans);
	}
	return 0;
}

posted @ 2021-02-02 20:07  tcswuzb  阅读(48)  评论(0编辑  收藏  举报