Judge:https://vjudge.net/problem/UVA-1152 题意:给定4个n元素集合A,B,C,D,要求分别从中选取一个元素a,b,c,d,使得四个数之和为零。求一共有多少种选法。
n的最大值为4000,时间限制为9000ms。
很明显四重循环枚举是肯定会超时。这里采用中途相遇法,枚举所有a+b并保存起来,然后再枚举-c-d与刚才的a+b对照。
对照的方法有很多种,可以使用二分查找或哈希表。
使用二分查找:(2910ms)
#include <iostream> #include <cstring> #include <algorithm> using namespace std; long long g_arrNum[4][4010]; long long g_arrSum[4000 * 4000 + 10], g_iTop = -1; int main() { int iDataTot; cin >> iDataTot; while (iDataTot--) { memset(g_arrNum, 0, sizeof(g_arrNum)); int iNumTot, iResult = 0, g_iTop = -1; cin >> iNumTot; for (int i = 1; i <= iNumTot; i++) for (int j = 1; j <= 4; j++) cin >> g_arrNum[j - 1][i]; for (int i = 1; i <= iNumTot; i++) for (int j = 1; j <= iNumTot; j++) g_arrSum[++g_iTop] = (g_arrNum[0][i] + g_arrNum[1][j]); sort(g_arrSum, g_arrSum + g_iTop + 1); for (int i = 1; i <= iNumTot; i++) for (int j = 1; j <= iNumTot; j++) iResult += upper_bound(g_arrSum, g_arrSum + g_iTop + 1, -(g_arrNum[2][i] + g_arrNum[3][j])) - lower_bound(g_arrSum, g_arrSum + g_iTop + 1, -(g_arrNum[2][i] + g_arrNum[3][j])); cout << iResult << endl; if (iDataTot) cout << endl; } return 0; }使用哈希表:(采用链表实现)(2300ms)
#include <iostream> #include <cstdio> #include <cstring> using namespace std; #define HASH_MAX 23456789 struct SHashNode { long iData; int iTime; SHashNode * pNext; }; int g_arrNum[4][4010]; SHashNode g_arrHash[HASH_MAX]; void InsertHash(long iData) { int i = (iData >= 0 ? iData % HASH_MAX : iData % HASH_MAX + HASH_MAX); SHashNode * pNode = &g_arrHash[i]; while (pNode->pNext) { if (pNode->pNext->iData == iData) { pNode->pNext->iTime++; return; } pNode = pNode->pNext; } pNode->pNext = new SHashNode; pNode->pNext->iTime = 1; pNode->pNext->iData = iData; pNode->pNext->pNext = 0; } int FindHash(long iData) { int i = (iData >= 0 ? iData % HASH_MAX : iData % HASH_MAX + HASH_MAX); SHashNode * pNode = &g_arrHash[i]; while (pNode->pNext) { if (pNode->pNext->iData == iData) return pNode->pNext->iTime; pNode = pNode->pNext; } return 0; } int main() { int iDataTot; cin >> iDataTot; while (iDataTot--) { memset(g_arrNum, 0, sizeof(g_arrNum)); memset(g_arrHash, 0, sizeof(g_arrHash)); int iNumTot, iResult = 0; cin >> iNumTot; for (int i = 1; i <= iNumTot; i++) for (int j = 1; j <= 4; j++) cin >> g_arrNum[j - 1][i]; for (int i = 1; i <= iNumTot; i++) for (int j = 1; j <= iNumTot; j++) InsertHash(g_arrNum[0][i] + g_arrNum[1][j]); for (int i = 1; i <= iNumTot; i++) for (int j = 1; j <= iNumTot; j++) iResult += FindHash(-(g_arrNum[2][i] + g_arrNum[3][j])); cout << iResult << endl; if (iDataTot) cout << endl; } return 0; }在本题目使用vector实现哈希表也是可以的,但时间略长,不过也长不了多少。