您的位置:首页 > 产品设计 > UI/UE

UVA - 1152 4 Values whose Sum is 0(hash || 二分)

2017-08-07 21:59 489 查看
题目传送门

题意

给四个集合,每个集合的元素个数小于4000,其中每个集合中的元素都是整数,让您求在这四个集合中各取一个数使的四个数的和为0.

分析

数据范围 如果用暴力枚举多有的可能性需要1e12的计算量肯定超时。利用中途相遇的思想可以分别枚举两个集合的所有可能性,然后从得到的两个结果集合中找,利用先排序然后二分查找可以达到n^2logn的复杂度。也可以自己实现一个hash表来统计。

二分

二分代码清晰,可以利用库中的函数使代码编写十分方便。容易理解。

for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
sum[num++] = A[i] + B[j];
sort(sum, sum + num);
long long cnt = 0;
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
cnt += upper_bound(sum, sum + num, -C[i]-D[j]) - lower_bound(sum, sum + num, -C[i] - D[j]);


hash实现

先上代码

//在hash表中插入数据, 其中idx全局变量每个测试例赋值1,也可以在hash数组开的足够大且存的数据不会溢出的时候不初始化
void insert(int summ)
{
int temp = summ > 0 ? summ : -summ;
int h = (temp%MAXN + temp / MAXN) % MAXN;
sum[idx] = summ;
pre[idx] = Hash[h];
Hash[h] = idx++;
}

//在查询表中查询数据
int find(int summ)
{
int cnt = 0;
int temp = summ > 0 ? summ : -summ;
int h = (temp%MAXN + temp / MAXN) % MAXN;
int u = Hash[h];
while (u)
{
if(sum[u] == summ)
cnt++;
u = pre[u];
}
return cnt;
}


其中的hash函数是我参考其他人的hash实现,所以就有一个缺点就是如果参数为负数的时候需要转为正数,然后在存的时候存原来的数据;

复杂度分析

二分的复杂度

利用二分的复杂度很容易分析,主要计算在一下代码中

for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)//O(n^2)
cnt += upper_bound(sum, sum + num, -C[i]-D[j]) - lower_bound(sum, sum + num, -C[i] - D[j]);     //O(logN)


代码中注释处写了复杂度,所以全局复杂度大概是O(n^2logN);其中n是集合中元素的个数,N是sum中元素的个数,无法确定。

利用hash实现的复杂度

当使用hash表来存的时候由于查询的时候可能复杂度略小;

for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)//O(n^2)
cnt += find(-C[i] - D[j]);//这个地方的复杂度需要讨论


代码中说需要讨论,但是我能力有限,没办法具体讨论

但可以确定的是查询某个值的个数的时候分两种情况

1. 该值的个数为0,O(1)

2. 该值存在,假设个数为m且表中该绝对值对应的值符号都相同 O(m)

3. 该值存在,但该绝对值对应的值符号有不同,假设个数分别为 a,b ; O(a + b);

最后所有的查询总计算量略大于hash表中存的元素的个数。所以复杂度近似O(n^2 + N);但最坏情况下却是O(n^2*N),这个时候可能会超时。当然这复杂度是建立在hash函数的基础上,如果能找到良好的hash函数,使±a对应不同的标签时就不会有最坏情况;计算量也达到最优。

完整ac代码


/*
problem:4 Values whose Sum is 0 UVA - 1152 https://vjudge.net/problem/36014/origin author:zxz
time:二分2600ms hash 2200ms
memory:
*/

#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <algorithm>
#include <map>
#include <set>
#include <stack>
#include <math.h>
#include <queue>
#include <string>
#include <sstream>
#include <vector>
#include <string.h>
#include <time.h>
using namespace std;

const int maxn = 4e3 + 5;
const int MAXN = maxn * maxn;
const int INF = 1<<28;
int A[maxn], B[maxn], C[maxn], D[maxn];
int sum[MAXN];//用于sort二分实现
int Hash[MAXN], pre[MAXN],idx;//用于hash实现

void insert(int summ)
{
int temp = summ > 0 ? summ : -summ;
int h = (temp%MAXN + temp / MAXN) % MAXN;
sum[idx] = summ;
pre[idx] = Hash[h];
Hash[h] = idx++;

}

int find(int summ)
{
int cnt = 0;
int temp = summ > 0 ? summ : -summ;
int h = (temp%MAXN + temp / MAXN) % MAXN;
int u = Hash[h];
while (u)
{
if(sum[u] == summ)
cnt++;
u = pre[u];
}
return cnt;
}

//hash实现
void solve1()
{
int T_T;
scanf("%d", &T_T);
int n = -1;
while (T_T--)
{
n == -1 ? 1 : puts("");
idx = 1;
sum[0] = INF;
memset(Hash, 0, sizeof Hash);
memset(pre, 0, sizeof pre);
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++)
insert(A[i] + B[j]);
long long cnt = 0;
for (int i = 0; i < n; i++)
for (int
4000
j = 0; j < n; j++)
cnt += find(-C[i] - D[j]);
printf("%lld\n", cnt);
}
}

//利用排序+二分实现
void solve()
{
int T_T;
scanf("%d", &T_T);
int n=-1;
while (T_T--)
{
n == -1 ? 1 : puts("");
scanf("%d", &n);
for (int i = 0; i < n; i++)
scanf("%d %d %d %d", &A[i], &B[i], &C[i], &D[i]);
int num = 0;
for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) sum[num++] = A[i] + B[j]; sort(sum, sum + num); long long cnt = 0; for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) cnt += upper_bound(sum, sum + num, -C[i]-D[j]) - lower_bound(sum, sum + num, -C[i] - D[j]);printf("%lld\n", cnt);
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("cin.txt", "r", stdin);
freopen("cout.txt", "w", stdout);
int mao = clock();
#endif
solve1();
#ifndef ONLINE_JUDGE
cerr << "Time:" << clock() - mao << "ms" << endl;
#endif
return 0;
}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  二分查找 hash