Uva1152 4 Values whose Sum is 0

题目大意

输入一个正整数N,接下来的N行每行输入4个数,从左到右分别是a,b,c,d。要求在N*4的
表中满足a+b+c+d=0条件的个数。N<=4000。

思路

需要转换一下思维,因为直接暴力遍历时N^4,可以分别遍历a+b和c+d的值,并且之存a+b的值,都存的话没必要而且浪费空间。之后算c+d时通过再来查找有多少a+b的值满足条件。

二分查找法:

首先将a+b的值sort一下,然后对于每一个c+d(之后算出来的),通过二分查找(也可以采用upper_bound和lower_bound)来确定满足条件的个数。最省空间,速度最慢,代码量最少,不过需要对细节进行处理。

Hash:

将a+b的值构建一个Hash表。然后对于每一个c+d的值只要O(1)的查询速度(平均来看)比二分法快10倍,速度最快,空间消耗最大,代码量较大。
Unorder_map:利用STL构建一个类似Hash表的数据结构,原理与Hash表类似,速度比二分法稍快一点,空间消耗是动态的,但是与Hash无太大区别(尤其是数据量极大时),但是最容易写。
1
上方的是unorder_map,下方是Hash。

代码(Hash)

#include<cstdio>
#include<algorithm>
#include<cstring>

using namespace std;

const int MAXN=4005;
int num[MAXN][4];
const int HashNum=2e7+3;
int HashOrd[HashNum];
int HashTable[HashNum];

void insert_Hash(int k){
    
    int h=(k%HashNum+HashNum)%HashNum;
    while(HashOrd[h]&&HashTable[h]!=k){
        h++;
        if(h>HashNum)h-=HashNum;
    }
    if(!HashOrd[h]){
        HashOrd[h]=1;
        HashTable[h]=k;
    }
    else HashOrd[h]++;
}
int Look_Table(int k){
    int h=(k%HashNum+HashNum)%HashNum;
    
    while(HashOrd[h]&&HashTable[h]!=k){
        h++;
        if(h>HashNum)h-=HashNum;
    }
    return HashOrd[h];
}
int main()
{
    int n,T;
    int a,b,c,d;
    scanf("%d",&n);
    bool ok=0;
    while(n--){
        memset(HashOrd,0,sizeof(HashOrd));
        memset(HashTable,0,sizeof(HashTable));
        scanf("%d",&T);
        for(int i=1;i<=T;i++){
            scanf("%d%d%d%d",&num[i][0],&num[i][1],&num[i][2],&num[i][3]);
        }
        for(int i=1;i<=T;i++){
            for(int j=1;j<=T;j++){
                insert_Hash(num[i][0]+num[j][1]);
            }
        }
        long long int ans=0;
        for(int i=1;i<=T;i++){
            for(int j=1;j<=T;j++){
                ans+=Look_Table(-num[i][2]-num[j][3]);
            }
        }
        if(ok)printf("\n");
        if(!ok)ok=1;
        printf("%lld\n",ans);
    }
}

代码(unorder_map)

#include<cstdio>
#include<unordered_map>
using namespace std;

const int MAXN=4005;
int box[MAXN][4];
unordered_map<int,int> Hash;
int main()
{
    int t,n;
    scanf("%d",&t);
    bool ok=0;
    while(t--){
        scanf("%d",&n);
        Hash.clear();
        for(int i=1;i<=n;i++){
           scanf("%d%d%d%d",&box[i][0],&box[i][1],&box[i][2],&box[i][3]);
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                Hash[box[i][0]+box[j][1]]++;
            }
        }
        long long int ans=0;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                ans+=Hash[-box[i][2]-box[j][3]];
            }
        }
        if(ok)printf("\n");
        ok=1;
        printf("%lld\n",ans);

    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值