题目
题目大意
数轴上有一些区间 (li,ri) ( l i , r i ) 在下雨,在某些点 pi p i 上有伞,伞的重量为 wi w i ,一个点上可能有多把伞,你想通过一个下雨的区间就必须有伞,你可以带很多伞,你行走一个单位长度需要花费你带的所有伞的重量和的代价,问从 0 0 走到的最小代价。
分析
dp[i][j] d p [ i ] [ j ] 表示拿着第 j j 把伞,走到点的最小代价(你随时都只最多拿一把伞,但是可能会换伞), j=0 j = 0 表示不拿伞。数据范围比较小,所以直接用 Rain[i] R a i n [ i ] 表示区间 (i−1,i) ( i − 1 , i ) 有没有下雨, Umb[i] U m b [ i ] 表示点 i i 上重量最小的伞的编号(显然你只会拿这个点上最轻的伞),表示这个点上没有伞。
分三种情况:
- 如果
(i−1,i)
(
i
−
1
,
i
)
没有下雨(
Rain[i]=0
R
a
i
n
[
i
]
=
0
),就可以在点
i−1
i
−
1
把伞扔掉,所以:
dp[i][0]=min(dp[i][0],dp[i−1][j])|Rain[i]=0 d p [ i ] [ 0 ] = m i n ( d p [ i ] [ 0 ] , d p [ i − 1 ] [ j ] ) | R a i n [ i ] = 0
- 不管
(i−1,i)
(
i
−
1
,
i
)
有没有下雨,都可以继续拿伞(前提是有伞即
j>0
j
>
0
),所以:
dp[i][j]=min(dp[i][j],dp[i−1][j]+W[j])|j>0 d p [ i ] [ j ] = m i n ( d p [ i ] [ j ] , d p [ i − 1 ] [ j ] + W [ j ] ) | j > 0
- 如果点
i−1
i
−
1
上有伞,你就可以换成这把伞(一定是换成
Umb[i−1]
U
m
b
[
i
−
1
]
),所以:
dp[i][Umb[i−1]]=min(dp[i][Umb[i−1]],dp[i−1][j]+W[Umb[i−1]])|Umb[i−1]>0 d p [ i ] [ U m b [ i − 1 ] ] = m i n ( d p [ i ] [ U m b [ i − 1 ] ] , d p [ i − 1 ] [ j ] + W [ U m b [ i − 1 ] ] ) | U m b [ i − 1 ] > 0
注意讨论的是从
i−1
i
−
1
走到
i
i
,如果是从走到
i+1
i
+
1
,用刷表法即可。
初始化
dp[0][0]=0
d
p
[
0
]
[
0
]
=
0
,
dp[i][j]=∞ (i≠0 or j≠0)
d
p
[
i
]
[
j
]
=
∞
(
i
≠
0
o
r
j
≠
0
)
。
代码
#include<cstdio>
#include<algorithm>
using namespace std;
#define MAXA 2000
#define MAXM 2000
#define INF 0x3f3f3f3f
int N,M,A;
bool Rain[MAXA+5];
int dp[MAXA+5][MAXM+5];
int Umb[MAXA+4],W[MAXM+5];
int main(){
scanf("%d%d%d",&A,&N,&M);
for(int i=1;i<=N;i++){
int l,r;
scanf("%d%d",&l,&r);
for(int j=l+1;j<=r;j++)
Rain[j]=1;
//Rain[i]: (i-1,i)
}
W[0]=INF;//方便更新Umb
for(int i=1;i<=M;i++){
int p;
scanf("%d%d",&p,&W[i]);
if(W[i]<W[Umb[p]])
Umb[p]=i;
}
fill(dp[0],dp[0]+M+1,INF);//注意这里
dp[0][0]=0;
for(int i=1;i<=A;i++){
fill(dp[i],dp[i]+M+1,INF);
for(int j=0;j<=M;j++){
//扔伞
if(!Rain[i])
dp[i][0]=min(dp[i][0],dp[i-1][j]);
//继续拿伞
if(j>0)
dp[i][j]=min(dp[i][j],dp[i-1][j]+W[j]);
//换伞(一定换成Umb[i-1])
if(Umb[i-1])
dp[i][Umb[i-1]]=min(dp[i][Umb[i-1]],dp[i-1][j]+W[Umb[i-1]]);
}
}
int Ans=INF;
for(int i=0;i<=M;i++)//统计Ans,看走到最后拿哪把伞(或者不拿)
Ans=min(Ans,dp[A][i]);
if(Ans==INF)
puts("-1");
else
printf("%d",Ans);
}