• [TJOI2010]分金币


    洛咕

    题意:现在有(n(n<=30))枚金币,它们可能会有不同的价值,现在要把它们分成两部分,要求这两部分金币数目之差不超过(1),问这样分成的两部分金币的价值之差最小是多少?

    分析:模拟退火从下午写到晚上,代码交了二十几份,最好成绩40分,果断放弃,开始思考搜索.因为(n<=30),最暴力的搜索也就(2^{30}),虽然这样会超时,但是我们想办法优化一下,剪一下枝,就能过去了.剪枝就直接写注释里面了.

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<map>
    #include<set>
    #define ll long long
    using namespace std;
    inline int read(){
        int x=0,o=1;char ch=getchar();
        while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
        if(ch=='-')o=-1,ch=getchar();
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*o;
    }
    const int N=50;
    const ll inf=1e18;
    ll n,tot,a[N],sum[N];
    inline ll dfs(int now,int x,ll X,int y,ll Y){
    //now:当前考虑到了第几个金币
    //x:第一部分的金币数量;X:第一部分的金币数目之和;y,Y同理
    	if(now>n)return abs(X-Y);//已经搜完了
    	if(x>n/2||y>n/2)return inf;//某一个部分多了,不合法
    	ll XX=X+sum[now+n/2-x-1]-sum[now-1];
    	if(XX<=tot-XX)return abs(XX-(tot-XX));
    //如果第一部分剩下的n/2-x个金币都选当前剩下的最大的 还是会比第二部分小,就直接这样选择了
    	XX=X+sum[n]-sum[n+x-n/2];
    	if(XX>=tot-XX)return abs(XX-(tot-XX));
    //如果第一部分剩下的n/2-x个金币都选当前剩下的最小的 还是会比第二部分大,也直接这样选择了
    	ll p=dfs(now+1,x+1,X+a[now],y,Y);//当前金币给第一部分
    	ll q=dfs(now+1,x,X,y+1,Y+a[now]);//当前金币给第二部分
    	return min(p,q);
    }
    int main(){
    	int T=read();
    	while(T--){
    		tot=0;n=read();//刚开始忘记tot=0,WA了几发
    		for(int i=1;i<=n;++i)a[i]=read(),tot+=a[i];
    		if(n&1)a[++n]=0;sort(a+1,a+n+1);reverse(a+1,a+n+1);
            for(int i=1;i<=n;++i)sum[i]=sum[i-1]+a[i];
    		printf("%lld
    ",dfs(1,0,0,0,0));
    	}
        return 0;
    }
    
    
  • 相关阅读:
    ASP.NET WebAPI Get和Post 传参总结
    关于EF第一次加载慢或过一段时间不访问时再次访问加载慢问题的总结
    jqthumb.js缩略图插件-让缩略图正常显示而不变形
    解决kindeditor编辑器中使用百度地图时不能拖动坐标的问题
    Jzoj3591 数据
    Jzoj3590 珠链
    Jzoj3590 珠链
    C++蜂鸣器歌曲1
    C++蜂鸣器歌曲1
    Jzoj2309 辽哥游戏
  • 原文地址:https://www.cnblogs.com/PPXppx/p/11674527.html
Copyright © 2020-2023  润新知