[返回模拟退火略解]

题目描述

今有 nnn 个数 {ai}\{a_i\}{ai​},把它们分成两堆{X},{Y}\{X\},\{Y\}{X},{Y},求一种分配使得∣∑i∈Xai−∑i∈Yai∣|\sum_{i\in X}{a_i}-\sum_{i\in Y}{a_i}|∣i∈X∑​ai​−i∈Y∑​ai​∣的值最小。

Solution 3878\text{Solution 3878}Solution 3878 解法一

模拟退火SA。

尝试重新排列 aaa,将 aaa 的前半部分分成一堆,后半部分分成一堆,求出解。

贴上 BriMon dalao的代码。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cstdlib>
#include <ctime>
#include <cmath>
using namespace std;
#define reg register
inline int read() {
int res = 0;char ch=getchar();bool fu=0;
while(!isdigit(ch)) {if(ch=='-')fu=1;ch=getchar();}
while(isdigit(ch)) res=(res<<3)+(res<<1)+(ch^48), ch=getchar();
return fu?-res:res;
} int T, n;
int a[35];
int ans; inline int Calc()
{
int res1 = 0, res2 = 0;
for (reg int i = 1 ; i <= n ; i ++)
if (i <= (n + 1) / 2) res1 += a[i];
else res2 += a[i];
return abs(res1 - res2);
} inline void SA()
{
double T = 2333.0;
while(T > 1e-9)
{
int x = rand() % ((n + 1) / 2) + 1, y = rand() % ((n + 1) / 2) + ((n + 1) / 2);
if (x <= 0 or x > n or y <= 0 or y > n) continue;
swap(a[x], a[y]);
int newans = Calc();
int dert = ans - newans;
if (dert > 0) ans = newans;
else if (exp((double)((double)dert/T)) * RAND_MAX <= rand()) swap(a[x], a[y]);
T *= 0.998;
}
} int main()
{
T = read();
srand((unsigned)time(NULL));
while(T--)
{
n = read();
for (reg int i = 1 ; i <= n ; i ++) a[i] = read();
ans = 1e9;
for (int i = 1 ; i <= 50 ; i ++) SA();
cout << ans << endl;
}
return 0;
}

Solution 3878\text{Solution 3878}Solution 3878 解法二

尝试 dfs 剪枝。

每个金币有取和不取 222 种状态,最多 303030 个金币,深搜需 2302^{30}230 的时间。然而可以优化。

按价值从大到小排序,你一不小心取的价值太大会被剪枝。

最多取 n2\frac{n}{2}2n​ 个金币,你取得太多是要被剪枝的。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm> #define reg register typedef long long ll;
int T,n;
ll a[40],s,ans;
bool b[40];
int hh[40]; int cmp(int a,int b){
return a>b;
}
ll h(int x,int y){
return hh[y]-hh[x-1];
}
ll dfs(int c,int x,ll X,int y,ll Y)
{
if(x>n/2||y>n/2) return ans;
ll nx=X+h(c,c+(n/2-x)-1);
if(nx<=s-nx) return(s-nx-nx);
nx=X+h(n-(n/2-x)+1,n);
if(nx>=s-nx) return(nx-(s-nx));
ll p=dfs(c+1,x+1,X+a[c],y,Y);
ll q=dfs(c+1,x,X,y+1,Y+a[c]);
if(p<q) return p;
return q;
}
int main(){
scanf("%d",&T);
while(T--){
scanf("%d",&n);
s=0;ans=1e17;
for(reg int i=1;i<=n;++i){
scanf("%lld",&a[i]);
s+=a[i];
}
if(n%2){
++n;
a[n]=0;
}
std::sort(a+1,a+n+1,cmp);
for(reg int i=1;i<=n;++i)
hh[i]=hh[i-1]+a[i];
printf("%lld\n",dfs(1,0,0,0,0));
}
}

luogu P3878 [TJOI2010]分金币的更多相关文章

  1. [洛谷P3878][TJOI2010]分金币

    题目大意:把$n(n\leqslant30)$个数分成两组,两组个数最多相差$1$,求出两组元素差的绝对值最小使多少 题解:模拟退火 卡点:$\exp$中的两个数相减写反,导致$\exp(x)$中的$ ...

  2. [luogu3878][TJOI2010]分金币【模拟退火】

    题目描述 现在有n枚金币,它们可能会有不同的价值,现在要把它们分成两部分,要求这两部分金币数目之差不超过1,问这样分成的两部分金币的价值之差最小是多少? 分析 根据模拟退火的基本套路,先随机分两堆金币 ...

  3. [TJOI2010]分金币

    嘟嘟嘟 看数据范围,就能想到折半搜索. 但怎么搜,必须得想清楚了. 假设金币总数为1000,有20个人,首先搜前10个人,把答案记下来.然后如果在后十个人中搜到了4个人,价值为120,那么我们应该在记 ...

  4. [Luogu3878] [TJOI2010]分金币

    题目描述 现在有n枚金币,它们可能会有不同的价值,现在要把它们分成两部分,要求这两部分金币数目之差不超过1,问这样分成的两部分金币的价值之差最小是多少? 输入输出格式 输入格式: 每个输入文件中包含多 ...

  5. Luogu-3878 [TJOI2010]分金币

    这题和在我长郡考试时的一道题思路差不多...考虑折半搜索,预处理左半边选的方案所产生的数量差值\(x\)以及价值差值\(y\),把\(y\)扔到下标为\(x\)的set里面,然后在搜索右半边,每搜出一 ...

  6. 分金币 bzoj 3293

    分金币(1s 128M)  coin [问题描述] 圆桌上坐着n个人,每人有一定数量的金币,金币总数能被n整除.每个人可以给他左右相邻的人一些金币,最终使得每个人的金币数目相等.你的任务是求出被转手的 ...

  7. 【BZOJ-3293&1465&1045】分金币&糖果传递×2 中位数 + 乱搞

    3293: [Cqoi2011]分金币 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 854  Solved: 476[Submit][Status] ...

  8. 【贪心+中位数】【UVa 11300】 分金币

    (解方程建模+中位数求最短累积位移) 分金币(Spreading the Wealth, UVa 11300) 圆桌旁坐着n个人,每人有一定数量的金币,金币总数能被n整除.每个人可以给他左右相邻的人一 ...

  9. 【BZOJ3293】分金币(贪心)

    [BZOJ3293]分金币(贪心) 题面 BZOJ 洛谷 题解 和上一题一样啊. #include<cstdio> #include<cmath> #include<al ...

随机推荐

  1. 二分练习题3 查找小于x的最大元素 题解

    题目描述 现在告诉你一个长度为 \(n\) 的有序数组 \(a_1, a_2, ..., a_n\) ,以及 \(q\) 次询问,每次询问会给你一个数 \(x\) ,对于每次询问,你需要输出数组 \( ...

  2. Centos第一次使用配置IP地址

    1.vim /etc/sysconfig/network-scripts/ifcfg-eth0   修改默认配置文件 TYPE=Ethernet BOOTPROTO=static #静态 可修改为[n ...

  3. Hive导入数据到HBase,再与Phoenix映射同步

    1. 创建HBase 表 create 'hbase_test','user' 2. 插入数据 put 'hbase_test','111','user:name','jack' put 'hbase ...

  4. ASP.NET Core 3.0 使用gRPC

    一.简介 gRPC 是一个由Google开源的,跨语言的,高性能的远程过程调用(RPC)框架. gRPC使客户端和服务端应用程序可以透明地进行通信,并简化了连接系统的构建.它使用HTTP/2作为通信协 ...

  5. [AWS] 01 - What is Amazon EMR

    [DE] ML on Big data: MLlib 关于 Amazon EMR 发布版本 利用 Amazon EMR 分析大数据 Amazon Athena 是一种交互式查询服务,让您能够轻松使用标 ...

  6. 接口测试时数据格式是json,如何将响应内容转换为字典解析

    import requests url = 'http://127.0.0.1:5050/index' def apiTestPost(url): datas = { 'a':'cisco3', 'b ...

  7. 站内搜索(ELK)之数据表字典类型字段的索引思路

    数据表字典类型的字段,如人员表中的“性别”.流程表中的“处理状态”,此类字段中的值高度重复,不建议放到可检索的索引字段中,原因如下: 若数据表字典类型字段的值索引到单独的索引字段中,因字典数据字符数一 ...

  8. Java 内存模型与内存结构

    Java内存模型 一.简介 Java内存模型(JMM)主要是为了规定线程和内存之间的一些关系:根据JMM的设计,系统存在一个主内存(Main Memory)和工作内存(Work Memory),Jav ...

  9. 使用.NET Core创建Windows服务(二) - 使用Topshelf方式

    原文:Creating Windows Services In .NET Core – Part 2 – The "Topshelf" Way 作者:Dotnet Core Tut ...

  10. redis列表底层实现之一——链表

    注意标题中的“之一”,那么什么情况下,列表会使用链表作为其数据结构呢? 答案就是——列表键包含了大量的元素,或者列表中包含的元素都是比较长的字符串. Ok,由于链表大家都比较熟悉,接下来就直接给出链表 ...