zoukankan      html  css  js  c++  java
  • [poj] 3977 Subset || 折半搜索MITM

    原题

    给定N个整数组成的数列(N<=35),从中选出一个子集,使得这个子集的所有元素的值的和的绝对值最小,如果有多组数据满足的话,选择子集元素最少的那个。


    n<=35,所以双向dfs的O(2^(n/2))可以直接解决问题。因为会爆空间,所以枚举前一半的二进制状态来完成dfs,并用map记录每个状态所用的个数,然后枚举后一半的状态在map中找第一个大于等于他的和第一个小于他的,比较这两个答案。

    注:long long 没有自带的abs,并且在define里要多打括号,因为优先度……

    #include<cstdio>
    #include<map>
    #define abs(x) ((x)>0?(x):-(x))
    typedef long long ll;
    using namespace std;
    ll n,a[40],ans,sum;
    int cnt;
    map <ll,int> mp;
    map <ll,int> :: iterator qwq;
    
    ll read()
    {
        ll ans=0,fu=1;
        char j=getchar();
        for (;(j<'0' || j>'9') && j!='-';j=getchar()) ;
        if (j=='-') j=getchar(),fu=-1;
        for (;j>='0' && j<='9';j=getchar()) ans*=10,ans+=j-'0';
        return ans*fu;
    }
    
    int main()
    {
        while (~scanf("%lld",&n) && n)
        {
    	mp.clear();
    	ans=0;
    	cnt=0;
    	for (int i=1;i<=n;i++)
    	    a[i]=read();
    	ans=abs(a[1]);
    	cnt=1;
    	for (int i=1,j,now,count;i<(1<<(n/2));i++)
    	{
    	    sum=0;
    	    j=i;
    	    now=0;
    	    count=0;
    	    while (j)
    	    {
    		if (j&1)
    		    sum+=a[now+1],count++;
    		j>>=1;
    		now++;
    	    }
    	    if (abs(sum)<ans)
    	    {
    		ans=abs(sum);
    		cnt=count;
    	    }
    	    else if (abs(sum)==ans) cnt=min(cnt,count);
    	    if (mp[sum])
    		mp[sum]=min(mp[sum],count);
    	    else 
    		mp[sum]=count;
    	}
    	for (int i=1,j,now,count;i<(1<<(n-n/2));i++)
    	{
    	    j=i;
    	    sum=0;
    	    count=0;
    	    now=0;
    	    while (j)
    	    {
    		if (j&1)
    		    sum+=a[now+n/2+1],count++;
    		j>>=1;
    		now++;
    	    }
    	    if (abs(sum)<ans)
    	    {
    		ans=abs(sum);
    		cnt=count;
    	    }
    	    else if (abs(sum)==ans) cnt=min(cnt,count);
    	    qwq=mp.lower_bound(-sum);
    	    ll nw;
    	    if (qwq!=mp.end())
    	    {
    		nw=sum+qwq->first;
    		nw=abs(nw);
    		if (nw<ans)
    		{
    		    ans=nw;
    		    cnt=qwq->second+count;
    		}
    		else if (nw==ans) cnt=min(cnt,qwq->second+count);
    	    }
    	    if (qwq!=mp.begin())
    	    {
    		qwq--;
    		nw=sum+qwq->first;
    		nw=abs(nw);
    		if (nw<ans)
    		{
    		    ans=nw;
    		    cnt=qwq->second+count;
    		}
    		else if (nw==ans) cnt=min(cnt,qwq->second+count);
    	    }
    	}
    	printf("%lld %d
    ",ans,cnt);
        }
        return 0;
    }
    
  • 相关阅读:
    python中os模块和sys模块的常见用法
    Python 十进制转换为二进制 高位补零
    Invalid prop: custom validator check failed for prop "pagerCount"的报错
    Centos7 安装使用virtualenvwrapper
    如何使用CORS解决跨域问题
    内置模块
    文件操作的相关
    小数据池的概念
    set()集合的概念与一般操作
    有关于dict(字典)的特性与操作方法
  • 原文地址:https://www.cnblogs.com/mrha/p/8017975.html
Copyright © 2011-2022 走看看