算法 1 2 3 4 5 6 7 8 9 10 11 12 int dfs (int u, int sum, int last) { if (u == n) { if (!sum) return 1 ; return 0 ; } int res = 0 ; for (int i = last; i <= sum; i ++) res += dfs (u + 1 , sum - i, i); return res; }
用一个数组来表示三个状态,代替这个序列是升序。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 int n;int state[N];void dfs (int u) { if (u > n) { for (int i = 1 ; i <= n; i ++) if (state[i] == 1 ) cout << i << ' ' ; puts ("" ); return ; } state[u] = 2 ; dfs (u + 1 ); state[u] = 0 ; state[u] = 1 ; dfs (u + 1 ); state[u] = 0 ; }
用位运算枚举第一行的开关按法,每个灯泡只按一次,第一行按完之后,如果有熄灭的灯泡就需要第二行再按下,来确保第一行熄灭的灯泡变亮
需要注意的点:①要用一个备份数组,因为按下会改变原数组的值。②最后不需要考虑了,直接遍历看还有没有熄灭的灯泡。
套用全排列模板,在此基础上更改即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 void dfs (int u, int last) { if (u > m) { for (int i = 1 ; i <= m; i ++) cout << path[i] << ' ' ; puts ("" ); return ; } for (int i = last + 1 ; i <= n; i ++) { if (!st[i]) { path[u] = i; st[i] = true ; dfs (u + 1 , i); st[i] = false ; } } }
深度优先搜索,void dfs(int u, int cnt)u
表示枚举到哪知猫了,cnt
表示现在有多少个缆车。有两种情况:①将猫加入已有的缆车当中。②将猫加入新的缆车。注意回溯复原。
优化:①如果枚举的最小还要大,那么直接返回。优先枚举较大的数。
图片详解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 #include <iostream> #include <algorithm> #include <cstring> using namespace std;const int N = 20 ;int g[N], cab[N];int n, w;int ans;void dfs (int u, int cnt) { if (cnt > ans) return ; if (u == n) { ans = min (ans, cnt); return ; } for (int i = 1 ; i <= cnt; i ++) { if (cab[i] + g[u] <= w) { cab[i] += g[u]; dfs (u + 1 , cnt); cab[i] -= g[u]; } } cab[cnt + 1 ] = g[u]; dfs (u + 1 , cnt + 1 ); cab[cnt + 1 ] = 0 ; } int main () { cin >> n >> w; for (int i = 0 ; i < n; i ++) cin >> g[i]; sort (g, g + n, greater <int >()); ans = n; dfs (0 , 0 ); cout << ans << endl; return 0 ; }