zl程序教程

您现在的位置是:首页 >  其它

当前栏目

Dreamoon and MRT(二元枚举)

and 枚举 二元
2023-09-27 14:27:46 时间

题目

数轴上有M个点a1、a2、...am,另有一个数列p1、p2、...pn,(1 ≤ pii ≤ M)。

给定d1、d2、...dn,对所有的 i (1 ≤ i ≤ n),已知 |api+1 - api| = di,求M得最少可能值。(1 ≤ n ≤ 25 ,1 ≤ ai ≤ 105)

原题链接:http://codeforces.com/group/gRkn7bDfsN/contest/212299/problem/B

思路

基本思路:枚举 api+1 在 api 的左边或右边,为了降低复杂度,强制第一次选向右(向左也可以)。

思路一:利用二进制+位运算,枚举所有的可能

O(2N-1N)

 1 #include<stdio.h>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cstring>
 5 using namespace std;
 6 
 7 const int SIZE = (25 * 100000) * 2 + 100;  //数轴的范围
 8 const int maxn = 25 + 10;
 9 int n, d[maxn];
10 int ans,cnt,vis[SIZE];
11 
12 void solve()
13 {
14     //对剩下m-1个选择进行枚举
15     for (int i = 0; i < (1 << (n - 1)); i++)
16     {
17         int v_num = 2;
18         cnt++;
19         int s = SIZE / 2 + d[0];
20         //for (int i = 0; i < SIZE; i++)  vis[i] = 0; //这种标记会导致T
21         vis[SIZE / 2] = cnt;            
22         vis[SIZE / 2 + d[0]] = cnt;        //强行规定第一次向左走
23 
24         for (int j = 0; j < n - 1; j++)
25         {
26             if (i & (1 << j))
27                 s += d[j + 1];
28             else
29                 s -= d[j + 1];
30             if (vis[s] != cnt) 
31             {
32                 v_num++;
33                 vis[s] = cnt;
34             }
35         }
36         ans = min(ans, v_num);
37     }
38 }
39 
40 int main()
41 {
42     scanf("%d", &n);
43     for (int i = 0; i < n; i++)
44         scanf("%d", &d[i]);
45     ans = n + 1;               //ans不会超过n+1
46     cnt = 0;
47     solve();
48     printf("%d\n", ans);
49     return 0;
50 }

 思路二:DFS尝试遍每一种情况

O(2N-1)

 1 #include<stdio.h>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cstring>
 5 using namespace std;
 6 
 7 const int SIZE = 25 * 100000 * 2 + 10;    //数轴的范围,SIZE/2相当于原点
 8 const int maxn = 25 + 10;
 9 int m, d[maxn];
10 int vis[SIZE];
11 int ans;
12 
13 //第cur+1个状态,x位置,顶点数v
14 void dfs(int cur, int x, int v)
15 {
16     if (cur == m)
17     {
18         ans = min(ans, v);
19         return;
20     }
21     int net = x + d[cur];
22     vis[net]++;        //不能只用0/1来区分
23     dfs(cur + 1, net, v + (vis[net] == 1));
24     vis[net]--;
25 
26     net = x - d[cur];
27     vis[net]++;
28     dfs(cur + 1, net, v + (vis[net] == 1));
29     vis[net]--;
30 }
31 
32 int main()
33 {
34     while (scanf("%d",&m) == 1 && m)
35     {
36         memset(vis, 0, sizeof(vis));
37         for (int i = 0; i < m; i++)
38             scanf("%d", &d[i]);
39         ans = m + 1;            //ans不会超过m+1
40         vis[SIZE / 2] = 1;
41         vis[SIZE / 2 + d[0]] = 1;        //强行规定第一次向有走
42         dfs(1, SIZE / 2 + d[0], 2);
43         printf("%d\n", ans);
44     }
45     return 0;
46 }