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;
}
posted @ 2024-10-24 10:55  Qian·JXのjoker  阅读(3)  评论(0编辑  收藏  举报