输入描述
第一行一个整数,表示独木桥的长度
第二行三个整数S T M,含义如上
第三行 M 个不同的正整数,表示这M个石子在数轴上的位置。
L -> [1,1000000]
S T -> [1,10]
M -> [1,100]
输出描述
一个整数,表示最少可以踩多少个石子
dfs深搜+剪枝:
前期思考:
1)由于本题的石头数量m比较少,因此会出现较多的空路,这里进行剪枝操作,因为大于s*t的空区间和s*t的区间等价,都不会导致石子数增加。
2)转移方程为:dp[i] = min(dp[i],dp[i-j]+visit[i]) s<j<t
具体含义为:前i个长度位置最少是dp[i]或dp[i]前s~t步内的最小踩石头数加i位置是否有石头,即能到i位置的所有位置最小的数
3)到最后L位置其实和最后一个石头起到L前的所有位置的最小踩石头数相同,遍历这些dp找到最小值即可
特别的,如果s == t 那就只有唯一的一个结果,遍历后得到踩石头数。
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
#define IOS ios::sync_with_stdio(false);
//代码预处理区
const int INF = 0x3f3f3f3f;
const int MAX = 1e6 + 7;
int stone[107], now[107];
int visited[MAX], dp[MAX];
//全局变量区
int main() {
IOS;
int l; cin >> l;
int s, t, m; cin >> s >> t >> m;
for (int i = 1; i <= m; i++) cin >> stone[i];
sort(stone + 1, stone + 1 + m);
if (s == t) {
int cnt = 0;
for (int i = 1; i <= m; ++i)
if (stone[i] % s == 0)cnt++;
cout << cnt << endl;
return 0;
}
now[0] = 0;
memset(visited, 0, sizeof visited);
for (int i = 1; i <= m; i++) {
int dis = stone[i] - stone[i - 1];
if (dis >= s * t) dis = s * t;
now[i] = now[i - 1] + dis;
visited[now[i]] = 1;
}
l = now[m] + s * t;
memset(dp, INF, sizeof dp);
dp[0] = 0;
for (int i = 1; i <= l; i++)
for (int j = s; j <= t; j++)
if (i >= j) dp[i] = min(dp[i], dp[i - j] + visited[i]);
int ans = INF;
for (int i = now[m]; i <= l; i++)
ans = min(ans, dp[i]);
cout << ans << endl;
return 0;
}
//函数区