P4044 [AHOI2014/JSOI2014]保龄球

模拟退火练习题。

考虑模拟退火,显然每次随机两个点并交换这两个点,不过注意要判断交换这两个点后序列是否仍然成立,也就是对于最后一轮是否交换后仍然成立,然后计算整个序列的贡献即可。

由于是模拟退火,所以显然考虑卡时,代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <cstdlib>
#include <random>
using namespace std;

constexpr int N(55);

int n, m, ans = 0;

clock_t c = clock();

inline int read()
{
	register char ch(getchar());
	register int x(0);
	while (ch < '0' || ch > '9')
	{
		ch = getchar();
	}
	while (ch >= '0' and ch <= '9')
	{
		x = (x << 1) + (x << 3) + (ch ^ 48);
		ch = getchar();
	}
	return x;
}

struct Node
{
	int a, b;
	Node(int _a, int _b) : a(_a), b(_b) {}
	Node()
	{
		a = b = 0;
	}
}q[N];

inline int calc()
{
	int res(0);
	for (register int i(1); i <= m; i++)
	{
		res += q[i].a + q[i].b;
		if (i <= n)
		{
			if (q[i].a == 10) res += q[i + 1].a + q[i + 1].b;
			else if (q[i].a + q[i].b == 10) res += q[i + 1].a;
		}
	}
	ans = max(ans, res);
	return res;
}

inline void getans()
{
	for (double t = 1e4; t > 1e-4; t *= 0.99)
	{
		int x = rand() % m + 1, y = rand() % m + 1, l(calc());
		swap(q[x], q[y]);
		if (n + (q[n].a == 10) == m)
		{
			int g(calc());
			int p(g - l);
			if (exp(p / t) < ((double)rand() / RAND_MAX)) swap(q[x], q[y]);
		}
		else swap(q[x], q[y]);
	}
}

int main()
{
	srand(time(NULL));
	n = read();
	for (register int i(1); i <= n; ++i)
	{
		int x(read()), y(read());
		q[i] = Node(x, y);
	}
	if (q[n].a == 10)
	{
		int x(read()), y(read());
		q[n + 1] = Node(x, y);
		m = n + 1;
	}
	else m = n;
	while ((double)(clock() - c) / CLOCKS_PER_SEC < 0.9) getans();
	printf("%d\n", ans);
	return 0;
}
posted @   HappyBobb  阅读(3)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示