题意:5个集合,每个集合最多200个数字,问是否每个集合挑一个数加起来和为0。
分析:显然n^5的程序果断超时,甚至n^3logn的二分也过不了。想n^3的方法,既然判断有没有,那么可以将两个两个的集合合并成两个大集合,再枚举最后一个集合,两个大集合排完序之后一个指针从开头最小开始,另一个从最大的开始,>0,大指针往左移,<0,小指针往右移,那么可以在线性时间求解,这贪心方法很巧妙!
另一种做法算是暴力+优化了,哈希表储存一个两个集合合并后大集合的数字,n^3暴力询问是否哈希表内存在它的相反数,哈希表用到链式前向星,总算有点理解了,贴张图:
收获:1. ”微调“贪心方法 2. 哈希表 + 链式前向星
代码1(贪心):
/************************************************ * Author :Running_Time * Created Time :2015-8-26 9:07:01 * File Name :HDOJ_4334.cpp ************************************************/ #include <cstdio> #include <algorithm> #include <iostream> #include <sstream> #include <cstring> #include <cmath> #include <string> #include <vector> #include <queue> #include <deque> #include <stack> #include <list> #include <map> #include <set> #include <bitset> #include <cstdlib> #include <ctime> using namespace std; #define lson l, mid, rt << 1 #define rson mid + 1, r, rt << 1 | 1 typedef long long ll; const int N = 2e2 + 10; const int INF = 0x3f3f3f3f; const int MOD = 1e9 + 7; ll a[5][N]; ll sum[2][N*N]; int main(void) { int T; scanf ("%d", &T); while (T--) { int n; scanf ("%d", &n); for (int i=0; i<5; ++i) { for (int j=0; j<n; ++j) { scanf ("%I64d", &a[i][j]); } } int tot = 0; for (int i=0; i<n; ++i) { for (int j=0; j<n; ++j) { sum[0][tot] = a[0][i] + a[1][j]; sum[1][tot++] = a[2][i] + a[3][j]; } } sort (sum[0], sum[0]+tot); sort (sum[1], sum[1]+tot); int cnt1 = 1, cnt2 = 1; for (int i=1; i<tot; ++i) { //其实离散化没什么优化 if (sum[0][i] != sum[0][i-1]) sum[0][cnt1++] = sum[0][i]; if (sum[1][i] != sum[1][i-1]) sum[1][cnt2++] = sum[1][i]; } bool flag = false; for (int i=0; i<n && !flag; ++i) { for (int j=0,k=cnt2-1; j<cnt1 && k>=0; ) { ll tmp = a[4][i] + sum[0][j] + sum[1][k]; if (tmp == 0) { flag = true; break; } else if (tmp < 0) j++; else k--; } } printf ("%s\n", flag ? "Yes" : "No"); } return 0; }
代码2(哈希表):
/************************************************ * Author :Running_Time * Created Time :2015-8-26 18:21:55 * File Name :D_2.cpp ************************************************/ #include <cstdio> #include <algorithm> #include <iostream> #include <sstream> #include <cstring> #include <cmath> #include <string> #include <vector> #include <queue> #include <deque> #include <stack> #include <list> #include <map> #include <set> #include <bitset> #include <cstdlib> #include <ctime> using namespace std; #define lson l, mid, rt << 1 #define rson mid + 1, r, rt << 1 | 1 typedef long long ll; const int N = 2e2 + 10; const int INF = 0x3f3f3f3f; const int MOD = 1e6 + 7; struct Hash_Table { struct Edge { ll x; int nex; }edge[MOD]; int head[MOD], E; void init(void) { memset (head, -1, sizeof (head)); E = 0; } void insert(ll x) { int u = (x % MOD + MOD) % MOD; for (int i=head[u]; ~i; i=edge[i].nex) { if (edge[i].x == x) return ; } edge[E].x = x; edge[E].nex = head[u]; head[u] = E++; } bool find(ll x) { int u = (x % MOD + MOD) % MOD; for (int i=head[u]; ~i; i=edge[i].nex) { if (edge[i].x == x) return true; } return false; } }ha; ll a[5][N]; int main(void) { int T; scanf ("%d", &T); while (T--) { int n; scanf ("%d", &n); for (int i=0; i<5; ++i) { for (int j=0; j<n; ++j) scanf ("%I64d", &a[i][j]); } ha.init (); for (int i=0; i<n; ++i) { for (int j=0; j<n; ++j) { ha.insert (a[0][i] + a[1][j]); } } bool flag = false; for (int i=0; i<n && !flag; ++i) { for (int j=0; j<n && !flag; ++j) { for (int k=0; k<n; ++k) { if (ha.find (-(a[2][i] + a[3][j] + a[4][k]))) { flag = true; break; } } } } puts (flag ? "Yes" : "No"); } return 0; }
时间: 2024-11-07 05:53:35