The sol to coin(搜索减脂版)
The sol to coin(搜索减脂版)
https://www.luogu.com.cn/problem/P3878
这题是模拟退火的板子,但这里先讲搜索(刚好练练搜索)
搜索减脂
\(1.\) 按价值从大到小排序,你一不小心取的价值太大会被剪枝
\(2.\)最多取n/2个金币,你取得太多是要被剪枝的
code with 注解
#include<bits/stdc++.h>
#define Ying using
#define AK namespace
#define IOI std;
Ying AK IOI
#define int long long
#define il inline
il int read(){
int x=0;int f=1;char c=getchar_unlocked();
while(c<'0'||c>'9'){
if(c=='-') f=-1;
c=getchar_unlocked();
}
while(c>='0'&&c<='9'){
x=x*10+c-'0';
c=getchar_unlocked();
}
return x*f;
}
il void print(int x){
if(x<0) putchar('-'),x=-x;
if(x>9) print(x/10);
putchar(x%10+'0');
}
int T;
int n;
const int N=35;
int a[N];
#define FOR(i,_l,_r) for(int i=(_l);i<=(_r);i++)
bool cmp(int a,int b){
return a>b;
}
int h[N];
int sum(int l,int r){
return h[r]-h[l-1];
}
const int Max=1e18;
int TOT;
int min(int a,int b){
if(a<=b) return a;
else return b;
}
//c-当前讨论第几个数,x-左边的数量,X-左边的值,y-右边的数量,Y-右边的值
int dfs(int c,int x,int X,int y,int Y){
if(x>n/2||y>n/2) return Max;
//讨论x最大都小于y
int XX=X+sum(c,c-1+(n/2-x));
if(XX<=TOT-XX) return (TOT-XX)-XX;
//讨论x最小都大于y
XX=X+sum(n-(n/2-x)+1,n);
if(XX>=TOT-XX) return XX-(TOT-XX);
//放在x上
int p=dfs(c+1,x+1,X+a[c],y,Y);
//放在y上
int q=dfs(c+1,x,X,y+1,Y+a[c]);
return min(p,q);
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("coin.in","r",stdin);
freopen("coin.out","w",stdout);
#endif
T=read();
while(T--){
n=read();
FOR(i,1,n) a[i]=read();
if(n&1) a[++n]=0;
sort(a+1,a+n+1,cmp);
FOR(i,1,n) h[i]=h[i-1]+a[i];
TOT=h[n];
print(dfs(1,0,0,0,0));puts("");
}
return 0;
}