那么双指针b的写法比a有什么好处呢?答案就是节省空间。如果我们使用的是双指针a,那储存方案的结构体必须包含 x,y,k 三种整数。注意其中的 k 最大只有 20,而我们却必须开一个 int 或是 short 来储存这个值,考虑到 20 这个值非常小,不管哪种数据类型都会浪费大量的空间。而采用双指针b后,我们的结构体中只会包含 x,y 两种整数, k 这个值储存在数组的下标中,只要你开的数组大小为 k 的最大值,就不会有任何的浪费。
具体的对比可以参考这个提交记录,可以发现相比双指针 a 的做法,双指针 b 的内存占用大约少了 17MB 左右
当然,代价也是有的,双指针 b 会稍微慢一些。我估计这主要出在双指针的环节。排序的部分甚至还会快一点。当然,不管哪种双指针,他们的理论复杂度都是一样的,因为每一种选取方案最多会被遍历到一次。
#include<bits/stdc++.h> usingnamespace std; #define ll long long #define rg register constint MAXN = 45;
structInstruct{ ll x, y; int k; constbooloperator < (Instruct b) const{ if(x != b.x) return x < b.x; if(y != b.y) return y < b.y; return k < b.k; } constbooloperator == (Instruct b) const{ return x == b.x && y == b.y; } }ins[MAXN];
vector<Instruct> fir_half, sec_half; ll ans[MAXN]; int mx_state; int n; int tar_x, tar_y;
voidvec_sum(int st, int ed, int cur_state, vector<Instruct> *cur_half){ //根据当前提供的状态 cur_state, 把选中的向量累加起来 //因为整个搜索的过程分成了两部分,所以需要参数表示是哪个部分,st, ed 表示的就是参与搜索的第一份向量,和最后一个。 ll tot_x = 0, tot_y = 0; int k = 0; int len = ed - st + 1; for(int i = 1; i <= len; i++){ if(cur_state & (1 << (i - 1))){ tot_x += ins[st + i - 1].x, tot_y += ins[st + i - 1].y; k++; } } (*cur_half).push_back({tot_x, tot_y, k}); }
voidstate_generator(bool mode){ //mode 表示当前处理的是前半部分还是后半部分,0是前半部分,1是后半部分 rg int cur_state = 0;//初始的状态,对应的就是什么都不选 int st, ed; vector<Instruct> *cur_half;//fir_half和sec_half储存这前半部分的方案和后半部分的方案 //cur_half就是当前这次搜索要把方案存到哪里 if(mode){ cur_half = &sec_half; st = n / 2 + 1, ed = n; if(n & 1) mx_state = mx_state * 2 + 1; //mx_state就是表示状态的数字最大能达到多少,它的初始值是 2^(n/2) 但是如果 n 是奇数 //后半部分会比前半部分多包含一个向量,所以还要把原来的 mx_state * 2 + 1 } else{ cur_half = &fir_half; st = 1, ed = n / 2; }
#include<bits/stdc++.h> usingnamespace std; #define ll long long #define rg register constint MAXN = 45;
structInstruct{ ll x, y; constbooloperator < (Instruct b) const{ if(x != b.x) return x < b.x; return y < b.y; } constbooloperator == (Instruct b) const{ return x == b.x && y == b.y; } }ins[MAXN]; vector<Instruct> fir_half[MAXN], sec_half[MAXN]; ll ans[MAXN]; int mx_state; int n; int tar_x, tar_y;
voidvec_sum(int st, int ed, int cur_state, vector<Instruct> *cur_half){ //根据当前提供的状态 cur_state, 把选中的向量累加起来 //因为整个搜索的过程分成了两部分,所以需要参数表示是哪个部分,st, ed 表示的就是参与搜索的第一份向量,和最后一个。 ll tot_x = 0, tot_y = 0; int k = 0; int len = ed - st + 1; for(int i = 1; i <= len; i++){ if(cur_state & (1 << (i - 1))){ tot_x += ins[st + i - 1].x, tot_y += ins[st + i - 1].y; k++; } } cur_half[k].push_back({tot_x, tot_y}); }
voidstate_generator(bool mode){ //mode 表示当前处理的是前半部分还是后半部分,0是前半部分,1是后半部分 rg int cur_state = 0;//初始的状态,对应的就是什么都不选 int st, ed; vector<Instruct> *cur_half; if(mode){ cur_half = sec_half; st = n / 2 + 1, ed = n; if(n & 1) mx_state = mx_state * 2 + 1; //mx_state就是表示状态的数字最大能达到多少,它的初始值是 2^(n/2) 但是如果 n 是奇数 //后半部分会比前半部分多包含一个向量,所以还要把原来的 mx_state * 2 + 1 } else{ cur_half = fir_half; st = 1, ed = n / 2; }