文章目录
- 1.二分查找法
- 1.1 思路:
- 1.2 AC代码
- 2.hash查找法
- 2.1 思路:
- 2.2 Wrong Answer 代码
- 2.3 Time Limit Exceeded 代码
- 2.4 偷懒失败,hash_map在poj中不存在
- 2.5 哈希表+二叉查找树(超时)
- 2.6 AC代码(哈希+数组法)
题目链接: http://poj.org/problem?id=2785
题目大意:给定不超过4000行4个数,每列挑出来1个,使之和为0,有多少种方案。
1.二分查找法
1.1 思路:
- 对左边两列的所有和求出来,右边两列所有的和的求出来再取负
- 右侧两列的值排序(进行二分查找)
- 对左边所有的和在右边的和中进行二分查找,并查找前后都满足要求的,计数即得答案
1.2 AC代码
/*** @description: 求四个数相加等于0的组合种数* @author: michael ming* @date: 2019/5/8 22:18* @modified by:*/
#include <iostream>
#include <memory.h>
#include <algorithm>using namespace std;
int a[4001], b[4001], c[4001], d[4001];
int ab[4000*4000+1], cd[4000*4000+1]; //存储a+b,c+d
int findSameValue(int value, int maxindex)//二分查找
{int low = 0, high = maxindex, mid, index, count=0;while(low <= high){mid = low + (high - low)/2;if(value == cd[mid]) //查找前后满足要求的个数{index = mid - 1;while(index >= 0 && value == cd[index--])count++;index = mid + 1;while(index <= high && value == cd[index++])count++;return count + 1;}else if(value < cd[mid])high = mid - 1;elselow = mid + 1;}return 0;
}
int main()
{int line, k=0;cin >> line;memset(ab, 0, sizeof(ab));memset(cd, 0, sizeof(cd));for(int i = 0; i < line; ++i){cin >> a[i] >> b[i] >> c[i] >> d[i];}for(int i = 0; i < line; ++i){for(int j = 0; j < line; ++j){ab[k] = a[i]+b[j];cd[k++] = -(c[i]+d[j]);}}sort(cd,cd+k); //二分查找的必要条件,有序int result = 0;for(int i = 0; i <= k-1; ++i)result += findSameValue(ab[i], k-1);cout << result << endl;return 0;
}
2.hash查找法
2.1 思路:
- 对左边两列的所有和求出来,右边两列所有的和的求出来再取负
- 对左侧两列的和存入哈希表
- 对右边两列的和在哈希表中查找
2.2 Wrong Answer 代码
(未解决冲突,并且hash后的值可能为负,作为数组下标不行,所以错误)
/*** @description: 4个数和为0的方案数,哈希法* @author: michael ming* @date: 2019/5/9 22:30* @modified by: */
#include <iostream>
#include <memory.h>
using namespace std;
int a[4001], b[4001], c[4001], d[4001];
int ab[4000*4000+1], cd[4000*4000+1]; //存储a+b,c+d
int *hasht = new int[16000057];
int offset = 1000000000;
int hashfunc(int &value)
{int mod = 16000057;return (value%mod + value/mod)%mod;
}
int main()
{int line, k=0, value;cin >> line;memset(hasht, 0, sizeof(hasht));for(int i = 0; i < line; ++i){cin >> a[i] >> b[i] >> c[i] >> d[i];}for(int i = 0; i < line; ++i){for(int j = 0; j < line; ++j){ab[k] = a[i]+b[j];value = ab[k]+offset;hasht[hashfunc(value)]++;cd[k++] = -(c[i]+d[j]);}}int result = 0;for(int i = 0; i < k; ++i){value = cd[i]+offset;if(hasht[hashfunc(value)])result += hasht[hashfunc(value)];}cout << result << endl;delete [] hasht;return 0;
}
2.3 Time Limit Exceeded 代码
/*** @description: 4个数和为0的方案数,哈希法* @author: michael ming* @date: 2019/5/9 22:30* @modified by: */
#include <iostream>
#include <math.h>
using namespace std;
struct linkedNode //链表节点
{pair<int, int> data;linkedNode *next;linkedNode():next(NULL), data(make_pair(0,0)){}
};
class linkedList //链表
{
public:linkedNode *head;linkedList(){head = new linkedNode(); //表头哨兵}~linkedList(){delete head;}
};
class linkedHash
{
private:linkedList *htList; //散列表链表数组int bucket; //散列表桶个数
public:linkedHash(int m):bucket(m){htList = new linkedList [bucket] ();}~linkedHash(){for(int i = 0; i < bucket; ++i){linkedNode *p = htList[i].head->next, *q = p;while(q != NULL){p = q;q = q->next;delete p;}}delete [] htList;}int hash(const int &key) const{return abs(key%bucket); //留余数法}linkedNode* find(const int &x) const{int i = hash(x);linkedNode *p = htList[i].head->next, *q = htList[i].head;while(p && p->data.first != x){q = p;p = p->next;}return q; //返回找到元素的前一个节点,或者没有找到,返回最后一个元素}linkedNode* insert(const int &x){int i = hash(x);linkedNode *p = htList[i].head, *q = p;while(q != NULL){p = q;q = q->next;if(q && q->data.first == x){q->data.second++;return q;}}p->next = new linkedNode();p->next->data.first = x;p->next->data.second++;return p->next;}
};
int a[4001], b[4001], c[4001], d[4001];
int ab[4000*4000+1], cd[4000*4000+1]; //存储a+b,c+d
int main()
{linkedHash ht(16000057);int line, k=0;cin >> line;for(int i = 0; i < line; ++i){cin >> a[i] >> b[i] >> c[i] >> d[i];}for(int i = 0; i < line; ++i){for(int j = 0; j < line; ++j){ab[k] = a[i]+b[j];ht.insert(ab[k]);cd[k++] = -(c[i]+d[j]);}}int result = 0;linkedNode* p;for(int i = 0; i < k; ++i){p = ht.find(cd[i])->next;if(p && p->data.first == cd[i])result += p->data.second;}cout << result << endl;return 0;
}
2.4 偷懒失败,hash_map在poj中不存在
/*** @description: 4个数和为0的方案数,哈希法* @author: michael ming* @date: 2019/5/9 22:30* @modified by: */
#include <iostream>
#include <hash_map>
//#include <unordered_map>
using namespace std;
int a[4001], b[4001], c[4001], d[4001];
int ab[4000*4000+1], cd[4000*4000+1]; //存储a+b,c+d
int main()
{__gnu_cxx::hash_map<int, int> ht;
// std::unordered_map<int, int> ht;int line, k=0;cin >> line;for(int i = 0; i < line; ++i){cin >> a[i] >> b[i] >> c[i] >> d[i];}for(int i = 0; i < line; ++i){for(int j = 0; j < line; ++j){ab[k] = a[i]+b[j];ht[ab[k]]++;cd[k++] = -(c[i]+d[j]);}}int result = 0;for(int i = 0; i < k; ++i){result += ht[cd[i]];}cout << result << endl;return 0;
}
2.5 哈希表+二叉查找树(超时)
可能是建立二叉树插入节点new太耗时了。
/*** @description: 4个数和为0的方案数,哈希法* @author: michael ming* @date: 2019/5/9 22:30* @modified by:*/
#include <iostream>
#include <math.h>
using namespace std;
class BSTNode
{
public:int data, count;BSTNode *left, *right;BSTNode():count(1), left(NULL), right(NULL){}BSTNode(const int& d, BSTNode *l = NULL, BSTNode *r = NULL){data = d; count = 1; left = l; right = r;}
};
class BST
{
private:BSTNode* root;int nodeLen;
public:BST():root(NULL){}~BST(){}void clear(BSTNode* nodeP){if(nodeP == NULL)return;clear(nodeP->left);clear(nodeP->right);delete nodeP;}BSTNode* get_root() const { return root; }bool isEmpty() const { return root == NULL; }BSTNode* search(const int& d) const{BSTNode* p = search(d, root);return p;}BSTNode* search(const int d, BSTNode* p) const{while(p != NULL){if(d == p->data)return p;else if(d < p->data)p = p->left;elsep = p->right;}return NULL;}void insert(const int d){BSTNode *p = root, *prev = NULL;while(p != NULL){prev = p;if(d < p->data)p = p->left;elsep = p->right;}if(root == NULL)root = new BSTNode(d);else if(d < prev->data)prev->left = new BSTNode(d);elseprev->right = new BSTNode(d);}
};class linkedHash
{
private:BST* ht_bstree; //散列表二叉树数组int bucket; //散列表桶个数
public:linkedHash(int m):bucket(m){ht_bstree = new BST [bucket] ();}~linkedHash(){for(int i = 0; i < bucket; ++i){ht_bstree[i].clear(ht_bstree[i].get_root());}delete [] ht_bstree;}int hash(const int &key) const{return abs((((key+1000000000)%bucket)+1357)%bucket); //留余数法}int find(const int &x) const{int i = hash(x);BSTNode *p = ht_bstree[i].search(x);if(p)return p->count;return 0;}void insert(const int x){int i = hash(x);BSTNode *p = ht_bstree[i].search(x);if(p)p->count++;elseht_bstree[i].insert(x);}
};
int a[4001], b[4001], c[4001], d[4001];
int ab[4000*4000+1], cd[4000*4000+1]; //存储a+b,c+d
int main()
{linkedHash ht(5000); //多次调整括号内数值,超时或者内存超限int line, k=0;cin >> line;for(int i = 0; i < line; ++i){cin >> a[i] >> b[i] >> c[i] >> d[i];}for(int i = 0; i < line; ++i){for(int j = 0; j < line; ++j){ab[k] = a[i]+b[j];ht.insert(ab[k]);cd[k++] = -(c[i]+d[j]);}}int result = 0;for(int i = 0; i < k; ++i){result += ht.find(cd[i]);}cout << result << endl;return 0;
}
2.6 AC代码(哈希+数组法)
/*** @description: poj 2785 哈希法,数组实现* @author: michael ming* @date: 2019/5/20 18:17* @modified by: */
#include <iostream>
using namespace std;
int a[4001], b[4001], c[4001], d[4001];
const int hashtablesize = 20000001;//保证一定的富裕,装载因子0.75左右
int hasht[hashtablesize];
int count[hashtablesize];
int offset = 1000000000; // 该数 > 2^29(加上他后,就没有负数了,求模后比较方便使用下标值)
int hashfunc(int value)
{return value%hashtablesize;
}
int hashfunc_other(int value)
{return (value+3)%hashtablesize;
}
void insert(int num)
{int num_init = num;num = hashfunc(num+offset);while(hasht[num] != offset && hasht[num] != num_init)//解决冲突,不等于初始值(够不着的大数)(值改了,位子被占了),且不等于映射的值(冲突了),第一次进入循环,第一个条件肯定不满足。{num = hashfunc_other(num);//冲突了,继续寻找别的下标(换一个函数,不然相同的模在这可能无限循环)}hasht[num] = num_init;count[num]++;
}
int find(int num)
{int num_init = num;num = hashfunc(num+offset);while(hasht[num] != offset && hasht[num] != num_init)num = hashfunc_other(num); //往下查找空位或者相等的值得位子if(hasht[num] == offset) //找到的是空位子,则没有匹配的和等于0return 0;else //找到了值相等的位子,把其对应的count位子里的个数返回return count[num];
}
int main()
{int line, k=0, value, i, j;cin >> line;for(i = 0; i < line; ++i){cin >> a[i] >> b[i] >> c[i] >> d[i];}for(i = 0; i < hashtablesize; ++i)hasht[i] = offset; //hash表每个元素初始化为offsetfor(i = 0; i < line; ++i){for(j = 0; j < line; ++j){value = a[i]+b[j];insert(value);}}int result = 0;for(i = 0; i < line; ++i){for(j = 0; j < line; ++j){value = (-c[i]-d[j]);result += find(value);}}cout << result << endl;return 0;
}