• poj 折半搜索


    poj2549 Sumsets

    题目链接: http://poj.org/problem?id=2549

    题意:给你一个含有n(n<=1000)个数的数列,问这个数列中是否存在四个不同的数a,b,c,d,使a+b+c=d;若存在则输出最大的d

    思路:完全暴力的话O(n^4),会T,可以考虑双向搜索,公式变形为a+b=d-c;分别枚举a+b和c-d,将值和下标存在结构体中,再二分查找即可

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<set>
    #include<vector>
    #include<map>
    using namespace std;
    struct Z{
    int s;
    int x;
    int y;
    bool operator < (const Z& b)const
    
        {
    
            return s < b.s;
    
        }
    }z[1000005],m[1000005];
    int n,a[1005];
    bool ok(Z& a, Z& b)
    
    {
        return a.x != b.x && a.y != b.y && a.x != b.y && a.y != b.x;
    }
    int main(){
        while((cin>>n)&&n!=0){
        int ans=-536870912;
        for(int i=0;i<n;i++)
            cin>>a[i];
        sort(a,a+n);
        int k=0;
        for(int i=0;i<n;i++)
           for(int j=i+1;j<n;j++){
            z[k].s=a[i]+a[j];
            z[k].x=i;
            z[k++].y=j;
           }
           int l=0;
        for(int i=0;i<n;i++)
           for(int j=i+1;j<n;j++){
            m[l].s=a[i]-a[j];
            m[l].x=i;
            m[l++].y=j;
            m[l].s=a[j]-a[i];
            m[l].x=j;
            m[l++].y=i;
           }
           sort(z,z+k);
           for(int i=0;i<l;i++){
            int d=lower_bound(z,z+k,m[i])-z;
            if(ok(z[d],m[i])&&z[d].s==m[i].s)
                ans=max(ans,z[d].s+a[m[i].y]);
           }
           if(ans!=-536870912)
           cout<<ans<<endl;
           else cout<<"no solution"<<endl;
        }
    }

    poj3977 Subset

    题目链接: http://poj.org/problem?id=3977

    题意:给你一个含n(n<=35)个数的数组,让你在数组中选出一个非空子集,使其元素和的绝对值最小,输出子集元素的个数以及元素和的绝对值,若两个子集元素和相等,输出元素个数小的那个。

    思路:如果直接暴力枚举,复杂度O(2^n),n为35时会超时,故可以考虑折半枚举,利用二进制将和以及元素个数存在两个结构体数组中,先预判 两个结构体是否满足题意,再将其中一个元素和取相反数后排序,因为总元素和越接近零越好,再二分查找即可,用lower_bound时考虑查找到的下标和他前一个下标,比较元素和以及元素个数,不断更新即可

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    struct Z{
    	long long int x;
    	int y;
    	bool operator < (const Z& b)const
        {
            if(x!=b.x)
            return x < b.x;
            return y<b.y;
        }
    }a[300005],b[300005];
    long long  int c[40];
    long long int abs1(long long int x){
        if(x<0)
            return -x;
        return x;
    }
    int main(){
        int n;
        while((cin>>n)&&n!=0){
            for(int i=0;i<300005;i++)
               a[i].x=a[i].y=b[i].x=b[i].y=0;
            long long int sum=1e17;
            int ans=40;
            for(int i=0;i<n;i++)
                cin>>c[i];
            int n1=n/2;
            for(int i=0;i<1<<n1;i++){
                for(int j=0;j<n1;j++){
                    if(i>>j&1&&(i!=0||j!=0)){
                        a[i-1].x+=c[j];
                        a[i-1].y++;
                    }
                }
    
            }
            int n2=n-n1;
            for(int i=0;i<(1<<n2);i++){
                for(int j=0;j<n2;j++){
                    if(i>>j&1&&(i!=0||j!=0)){
                        b[i-1].x+=c[j+n1];
                        b[i-1].y++;
                    }
                }
    
            }
          for(int i=0;i<(1<<n1)-1;i++){
            if(abs1(a[i].x)<sum){
                sum=abs1(a[i].x);
                ans=a[i].y;
            }
            else if(abs1(a[i].x)==sum&&a[i].y<ans){
                ans=a[i].y;
                sum=abs1(a[i].x);
            }
          }
        for(int i=0;i<(1<<n1)-1;i++)
            a[i].x=-a[i].x;
          for(int i=0;i<(1<<n2)-1;i++){
            if(abs1(b[i].x)<sum){
                sum=abs1(b[i].x);
                ans=b[i].y;
            }
            else if(abs1(b[i].x)==sum&&b[i].y<ans){
                ans=b[i].y;
                sum=abs1(b[i].x);
            }
          }
    
            sort(a,a+(1<<n1)-1);
            sort(b,b+(1<<n2)-1);
            for(int i=0;i<(1<<n1)-1;i++){
                int t=lower_bound(b,b+(1<<n2)-1,a[i])-b;
                if(t>0){
                	if(abs1(b[t-1].x-a[i].x)<sum){
                   		sum=abs1(b[t-1].x-a[i].x);
                    	ans=b[t-1].y+a[i].y;
                	}
                	else if(abs1(b[t-1].x-a[i].x)==sum&&b[t-1].y+a[i].y<ans){
                    	sum=abs1(b[t-1].x-a[i].x);
                    	ans=b[t-1].y+a[i].y;
                	}
                }
                if(t<(1<<n2)-1){
                    if(abs1(b[t].x-a[i].x)<sum){
                    sum=abs1(b[t].x-a[i].x);
                    ans=b[t].y+a[i].y;
                }
                else if(abs1(b[t].x-a[i].x)==sum&&b[t].y+a[i].y<ans){
                    sum=abs1(b[t].x-a[i].x);
                    ans=b[t].y+a[i].y;
                }
                }
    
            }
        cout<<sum<<" "<<ans<<endl;
        }
    }

    poj2785 4 Values whose Sum is 0

    题目链接: http://poj.org/problem?id=2785

    挑战P160

    题意:给你各有n个整数的四个数组,问从每个数列中取出一个数使四个数之和为0,问共有多少种取法,一个数列中有多个相同的数字时,将他们当成不同的数字看待,1<=n<=4000;

    思路:完全暴力枚举O(n^4)肯定会超时,可以考虑拆成两半后枚举设四个数a+b+c+d=0,先将a+b所有组合存在一个数组中并排序O(n^2),再枚举c+d(O(n^2)),对于每个c+d,在a+b的数列中二分搜索-(c+d),总复杂度O(n^2*log n);

    直接贴书上代码:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    using namespace std;
    int a[4005],b[4005],c[4005],d[4005],cd[16000005];
    int main(){
        int n;
        scanf("%d",&n);
        for(int i=0;i<n;i++)
            scanf("%d%d%d%d",&a[i],&b[i],&c[i],&d[i]);
            for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
            cd[i*n+j]=c[i]+d[j];
        sort(cd,cd+n*n);
        long long ans=0;
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++){
                    int CD=-(a[i]+b[j]);
            ans+=upper_bound(cd,cd+n*n,CD)-lower_bound(cd,cd+n*n,CD);
            }
        printf("%lld
    ",ans);
    }
    

      

  • 相关阅读:
    微信支付v2开发(11) Native支付
    微信公众平台开发(103) 四六级成绩查询
    教爸爸妈妈用微信
    微信支付开发(12) 认清微信支付v2和v3
    微信公众平台卡券功能
    用网页 实现断点续传 (HTTP)
    用SpringBoot 实现断点续传 (HTTP)
    用SpringMVC 实现断点续传 (HTTP)
    用vue 实现断点续传 (HTTP)
    用html5 实现断点续传 (HTTP)
  • 原文地址:https://www.cnblogs.com/dlutjwh/p/10987735.html
Copyright © 2020-2023  润新知