题意:坐标轴[1,m]上有很多信号基站,每个基站都有一个以其坐标为中心的覆盖范围,覆盖范围关于中心对称,现在让增加一些基站的信号覆盖范围,使[1,m]范围全部覆盖,求最小代价。
思路:第一眼看像贪心,发现假了,如果对基站坐标从小到大排个序,从前往后贪的话会有问题,比如第三个样例就过不去。那只能dp做了。
(1)可以从前往后推,我们加一个基站在0点处,覆盖范围为][0,0],定义dp[i]为从点0覆盖到点i所用最小花费。
那么可以得到状态转移方程:
d p [ i ] = d p [ i − 1 ] dp[i]=dp[i-1] dp[i]=dp[i−1](如果点i原本就被覆盖)
点i没有被覆盖就去i前面找基站,假设位置为j,覆盖范围为 [ l , r ] [l,r] [l,r],则:
d p [ i ] = m i n ( d p [ i ] , d p [ m a x ( 0 , l − ( i − r ) − 1 ) ] + ( i − r ) ) dp[i]=min(dp[i],dp[max(0,l-(i-r)-1)]+(i-r)) dp[i]=min(dp[i],dp[max(0,l−(i−r)−1)]+(i−r))
dp[m]即为结果
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,int> P;
#define ft first
#define sd second
const int maxn=1e5+10;
const ll inf=1e15;
int n,m;
struct node{
int l,r;
}no[maxn];
int dp[maxn];
int main()
{
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++){
int x,s;
scanf("%d%d",&x,&s);
no[i].l=max(0,x-s);
no[i].r=min(m,x+s);
}
dp[0]=0;
for(int i=1;i<=m;i++){
dp[i]=i;//初始化为最大花费
for(int j=0;j<n;j++){
if(no[j].l<=i&&no[j].r>=i)dp[i]=min(dp[i],dp[i-1]);
else if(no[j].r<i){//去前面找个最优的基站进行扩建
int u=i-no[j].r;
dp[i]=min(dp[i],dp[max(no[j].l-u-1,0)]+u);
}
}
}
cout<<dp[m]<<'\n';
return 0;
}
(2)也可以从后往前推,我们加一个基站在m+1点处,覆盖范围为][m+1,m+1],定义dp[i]为从点i+1覆盖到点m+1所用最小花费。
那么可以得到状态转移方程:
d p [ i ] = d p [ i + 1 ] dp[i]=dp[i+1] dp[i]=dp[i+1](如果点i+1原本就被覆盖)
点i+1没有被覆盖就去i点后面找基站,假设位置为j,覆盖范围为 [ l , r ] [l,r] [l,r]则:
d p [ i ] = m i n ( d p [ i ] , d p [ m i n ( 0 , r + ( l − i − 1 ) ) ] + ( l − i − 1 ) ) dp[i]=min(dp[i],dp[min(0,r+(l-i-1))]+(l-i-1)) dp[i]=min(dp[i],dp[min(0,r+(l−i−1))]+(l−i−1))
dp[0]即为结果
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,int> P;
#define ft first
#define sd second
const int maxn=1e5+10;
const ll inf=1e15;
int n,m;
struct node{
int l,r;
}no[maxn];
int dp[maxn];
int main()
{
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++){
int x,s;
scanf("%d%d",&x,&s);
no[i].l=max(0,x-s);
no[i].r=min(m,x+s);
}
dp[m]=0;
for(int i=m-1;i>=0;i--){
dp[i]=m-i;//初始化为最大花费
for(int j=0;j<n;j++){
if(no[j].l<=i+1&&no[j].r>=i+1)dp[i]=min(dp[i],dp[i+1]);
else if(no[j].l>i){//去后面找个最优的基站进行扩建
int u=no[j].l-i-1;
dp[i]=min(dp[i],dp[min(no[j].r+u,m)]+u);
}
}
}
cout<<dp[0]<<'\n';
return 0;
}