[返回模拟退火略解]

题目描述

今有 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. MOOC C++笔记(二):类和对象基础

    第二周:类和对象基础 面向对象程序设计的四个基本特点 抽象.封装.继承.多态. 面向对象程序设计的过程 1.从客观事物抽象出类 抽象出的事物带有成员函数与成员变量(类似于带函数的结构体) 成员变量和成 ...

  2. JDK 13 都已经发布了,Java 8 依然是最爱

    在 JDK 版本的世界里,从来都是 Oracle 发他的新版本,我们继续用我们的老版本.三年之前用 JDK 7,后来终于升级到了 JDK 8.自从升级了没多久,JDK 就开始了半年发一个新版本的节奏, ...

  3. el-table合并行并自定义某一列或几列

    在el-table的官方组件中并没有看到具体的合并行或者列及自定义表格内容,于是就自己写了一个效果如下所示. 这种对左侧内容要求比较高,要求行合并,并要自定义一些内容.下面说一下具体方法及代码写法. ...

  4. APP自动化测试的环境配置

    什么是Appium? 第三方自动化框架(工具),扩充了selenium webdriver 协议,在原有的基础上添加了移动端测试API selenium webdriver 指定了客户端到服务端的协议 ...

  5. Nginx反向代理之动静分离

    我们已经知道了什么是正向代理与反向代理,这次我们就讲一下Nginx的动静分离的案例,其实质运用的就是反向代理,专门用一台服务器代理服务器上的图片资源. 想使用代理必然要配置代理,配置反向代理,必须要用 ...

  6. MySql错误处理--错误代码和消息

      附录B:错误代码和消息 目录 B.1. 服务器错误代码和消息 B.2. 客户端错误代码和消息 本章列出了当你用任何主机语言调用MySQL时可能出现的错误.首先列出了服务器错误消息.其次列出了客户端 ...

  7. eclipse与hadoop集成,运行wordCount1

    搭好了hadoop集群之后,就该使用它了 第一步:下载hadoop eclipse的插件,将它放到eclipse\plugins的目录下,然后重启eclipse,点击windows->show ...

  8. git基本命令整合

    基础命令 用户设置 $ git config --global user.name "Your Name" $ git config --global user.email &qu ...

  9. JS 取整、取余

    一.取整 1. 取整 // 丢弃小数部分,保留整数部分 parseInt(7/2) // 3 2. 向上取整 // 向上取整,有小数就整数部分加1 Math.ceil(7/2) // 4 3. 向下取 ...

  10. WordPress新用户注册时提示“您的密码重设链接无效”

    在使用Wordpress密码找回功能及新用户注册邮件中的重置密码链接时,Wordpress提示“您的密码重设链接无效,请在下方请求新链接.”.“该key似乎无效”.“invalid key”. 这个其 ...