E. Antenna Coverage(Codeforces Round #600 (Div. 2))(dp-贪心)

E. Antenna Coverage(Codeforces Round #600 (Div. 2))(dp-贪心)

在这里插入图片描述

题意

n n 个天线,每个天线有一定的半径可以覆盖一位数轴上的某段区域。现在你可以执行一个操作使某个天线的覆盖半径增加 1 1 ,你可以执行任意次这样的操作。

现在问你最少执行多少次可以覆盖从 1 m 1-m 的所有区域?

题解

请结合代码注释进行理解

在这里插入图片描述

代码

#include<bits/stdc++.h>
#define maxn 200010
using namespace std;

int n, m, dp[maxn], s[maxn], x[maxn];	//dp[i]表示覆盖到i位置所需的最小花费
int main() {
	cin >> n >> m;
	for (int i = 1; i <= m; i++)
		dp[i] = i;
	for (int i = 1; i <= n; i++)
		cin >> x[i] >> s[i];
	for (int i = 1; i <= m; i++)
		for (int j = 1; j <= n; j++) {
			if (i >= x[j])
				dp[i] = min(dp[i], dp[max(2 * x[j] - i - 1, 0)]/*覆盖到左边缘所需的最小花费*/ + max(i - x[j] - s[j], 0)/*从右边缘覆盖到i所需的花费*/);
			else
				dp[i] = min(dp[i], dp[max(x[j] - s[j] - 1, 0)]);	//
		}
	cout << dp[m] << endl;
	return 0;
}

另一种解法

通过dfs进行记忆化搜索,区别在于这个是倒着推的,上面那个是正着推的。

代码

#include <bits/stdc++.h>
using namespace std;
#define fi first
#define sec second
typedef int ll;
typedef long double  ld;
#define pii pair<ll,ll> 
#define fast ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define mem(a,b) memset(a,b,sizeof(a))
ll dp[2][80][100001];	//dp[i][j][k]表示第j个天线用过(i = 1)/没用过(i = 0)时从k覆盖到m的最小花费
ll n, m;
pii arr[100];
ll func(ll pehlibaar, ll index, ll reach) {
	if (reach > m) return 0;	//如果已经覆盖到了m,就不需再额外覆盖
	if (index == n) return 1e7;
	ll &ret = dp[pehlibaar][index][reach];
	if (ret != -1) return ret;	//记忆化搜索
	ret = func(0, index + 1, reach);	//优先考虑后面的天线,得出后面的天线后的最优结果后记录数据,然后用之前得出过的最优结果
	if (pehlibaar == 0) {	//如果当前天线还没用过
		ll x = arr[index].fi - arr[index].sec;	//第index个天线的覆盖下限
		if (x >= reach) {	//如果当前要覆盖的位置在第index个天线的下限之前,说明当前要覆盖的位置离index天线之间该有距离离,需要加上这部分距离,即(x - reach)
			ret = min(ret, func(1, index, arr[index].fi + arr[index].sec + x - reach + 1) + x - reach);
		}
		else if (reach <= arr[index].fi + arr[index].sec) {	//如果当前要覆盖的位置正好在第index天线的下限上或者在其之后,则不需要不上中间的距离,只需要加上这个天线覆盖的最小花费
			ret = min(ret, func(1, index, arr[index].fi + arr[index].sec + 1));	//1表示第index已经用过了,只需要把reach往后推即可
		}
	}
	else {	//如果当前天线已经用过了,那么就把天线扩大一下继续用
		ret = min(ret, func(1, index, reach + 1) + 1);
	}
	return ret;
}
signed main() {
	freopen("in.txt", "r", stdin);
	fast;
	cin >> n >> m;
	ll i;
	for (i = 0; i < n; i++)
		cin >> arr[i].fi >> arr[i].sec;
	sort(arr, arr + n);
	mem(dp, -1);
	cout << func(0, 0, 1);
}
发布了163 篇原创文章 · 获赞 54 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/weixin_42856843/article/details/103115265