[luogu3878][TJOI2010]分金币【模拟退火】
题目描述
现在有n枚金币,它们可能会有不同的价值,现在要把它们分成两部分,要求这两部分金币数目之差不超过1,问这样分成的两部分金币的价值之差最小是多少?
分析
根据模拟退火的基本套路,先随机分两堆金币,然后每一次随机从两堆中取出一个,进行交换,看看答案是否更优【太简单了,不多赘述】
ac代码
#include <bits/stdc++.h>
#define ms(a, b) memset(a, b, sizeof(a))
#define inf 0x3f3f3f3f
#define db double
using namespace std;
inline char gc() {
static char buf[1 << 16], *S, *T;
if (S == T) {
T = (S = buf) + fread(buf, 1, 1 << 16, stdin);
if (T == S) return EOF;
}
return *S ++;
}
template <typename T>
inline void read(T &x) {
T w = 1;
x = 0;
char ch = gc();
while (ch < '0' || ch > '9') {
if (ch == '-') w = -1;
ch = gc();
}
while (ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + (ch ^ 48), ch = gc();
x = x * w;
}
template <typename T>
void write(T x) {
if (x < 0) putchar('-'), x = -x;
if (x > 9) write(x / 10);
putchar(x % 10 + 48);
}
#define N 105
int n, ans;
int a[N];
int calc() {
int res1 = 0, res2 = 0;
for (int i = 1; i <= n; i ++)
if (i <= (n + 1) / 2) res1 += a[i];
else res2 += a[i];
return abs(res1 - res2);
}
db Rand() {
return rand() % 10000 / 10000.0;
}
void SA(db T) {
while (T > 1e-3) {
int x = rand() % ((n + 1) / 2) + 1, y = rand() % ((n + 1) / 2) + ((n + 1) / 2);
if (x <= 0 || x > n || y <= 0 || y > n) continue;
swap(a[x], a[y]);
int res = calc();
if (ans > res) ans = res;
else if ((exp((1.0 * ans - 1.0 * res) / T)) <= Rand()) swap(a[x], a[y]);
T *= 0.98;
}
}
int main() {
// freopen("coin.in","r",stdin);
// freopen("coin.out","w",stdout);
srand(15346301);
int cas;
read(cas);
for (int _t = 1; _t <= cas; _t ++) {
read(n);
for (int i = 1; i <= n; i ++) read(a[i]);
ans = inf;
for (int i = 1; i <= 150; i ++) SA(10000);
printf("%d\n", ans);
}
return 0;
}
[luogu3878][TJOI2010]分金币【模拟退火】的更多相关文章
- [Luogu3878] [TJOI2010]分金币
题目描述 现在有n枚金币,它们可能会有不同的价值,现在要把它们分成两部分,要求这两部分金币数目之差不超过1,问这样分成的两部分金币的价值之差最小是多少? 输入输出格式 输入格式: 每个输入文件中包含多 ...
- Luogu-3878 [TJOI2010]分金币
这题和在我长郡考试时的一道题思路差不多...考虑折半搜索,预处理左半边选的方案所产生的数量差值\(x\)以及价值差值\(y\),把\(y\)扔到下标为\(x\)的set里面,然后在搜索右半边,每搜出一 ...
- luogu P3878 [TJOI2010]分金币
[返回模拟退火略解] 题目描述 今有 nnn 个数 {ai}\{a_i\}{ai},把它们分成两堆{X},{Y}\{X\},\{Y\}{X},{Y},求一种分配使得∣∑i∈Xai−∑i∈Yai∣|\ ...
- [TJOI2010]分金币
嘟嘟嘟 看数据范围,就能想到折半搜索. 但怎么搜,必须得想清楚了. 假设金币总数为1000,有20个人,首先搜前10个人,把答案记下来.然后如果在后十个人中搜到了4个人,价值为120,那么我们应该在记 ...
- [洛谷P3878][TJOI2010]分金币
题目大意:把$n(n\leqslant30)$个数分成两组,两组个数最多相差$1$,求出两组元素差的绝对值最小使多少 题解:模拟退火 卡点:$\exp$中的两个数相减写反,导致$\exp(x)$中的$ ...
- 分金币 bzoj 3293
分金币(1s 128M) coin [问题描述] 圆桌上坐着n个人,每人有一定数量的金币,金币总数能被n整除.每个人可以给他左右相邻的人一些金币,最终使得每个人的金币数目相等.你的任务是求出被转手的 ...
- 【BZOJ-3293&1465&1045】分金币&糖果传递×2 中位数 + 乱搞
3293: [Cqoi2011]分金币 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 854 Solved: 476[Submit][Status] ...
- 【贪心+中位数】【UVa 11300】 分金币
(解方程建模+中位数求最短累积位移) 分金币(Spreading the Wealth, UVa 11300) 圆桌旁坐着n个人,每人有一定数量的金币,金币总数能被n整除.每个人可以给他左右相邻的人一 ...
- 【BZOJ3293】分金币(贪心)
[BZOJ3293]分金币(贪心) 题面 BZOJ 洛谷 题解 和上一题一样啊. #include<cstdio> #include<cmath> #include<al ...
随机推荐
- p201 谱集是闭集 有界集
1 是如何来的? 由1 如何推出 2 2 是如何来的?谢谢 1.σ是的补集 入属于ρ 稠密是因为 T有定义的地方,λI-T都有定义,有界是因为 所以 然后 ρ是σ的补集 模比||T||大的数都 ...
- 配置react-sass
在配置react-sass时遇到很多坑其中 一条如果你的.scss文件失效 请一定要在fileloader之前配置该sass-loader 配置文件如下 基于你不熟悉webpack 容易出这个错误
- linux redis服务安装
redis下载 官网地址:https://redis.io/download 在Linux下安装Redis非常简单,具体步骤如下(官网有说明): 1.下载源码,解压缩后编译源码. $ wget htt ...
- python之路--网络通信协议
一 . osi七层协议 互联网协议按照功能不同分为osi七层或tcp/ip五层或tcp/ip四层 二 . tcp三次握手和四次挥手 我们知道网络层,可以实现两个主机之间的通信.但是这并不具体,因为,真 ...
- python设计模式第二十二天【备忘录模式】
1.应用场景 (1)能保存对象的状态,并能够恢复到之前的状态 2.代码实现 #!/usr/bin/env python #! _*_ coding:UTF-8 _*_ class Originator ...
- PHPCMS的使用
1.下载安装phpcms 下载完后解压将install_packages上传到服务器并重命名为phpcms_test: 更改目录文件系统权限: chmod -R 777 phpcms_test 配置n ...
- python requests上传文件 tornado 接收文件
requests 上传文件 import requests def images(): url = 'http://127.0.0.1:8889/upload/image' files = {'fil ...
- Opencv画图操作
1. 画矩形 MyRect rect;rect.left = 5;rect.top = 5;rect.right = 100;rect.bottom = 100;IplImage * pColorIm ...
- poj-1273(最大流)
题解:纯板子题... EK算法 #include<iostream> #include<algorithm> #include<cstring> #include& ...
- Django实现Rbac权限管理
权限管理 权限管理是根据不同的用户有相应的权限功能,通常用到的权限管理理念Rbac. Rbac 基于角色的权限访问控制(Role-Based Access Control)作为传统访问控制(自主访问, ...