原题链接:洛谷P1052 [NOIP2005 提高组] 过河
洛谷上一位大佬写得很好:Actinoi’s blog: 过河
我的AC代码:
#include <bits/stdc++.h>
#define maxl 1000000005
#define maxm 105
using namespace std;
int L;
int s, t, m;
int stone[maxm];
int bridge[110*110];
int dp[110*110];
/*
这题关键在于离散化
当两个石子之间的距离很远时,把中间的无相关的距离缩减掉
本题的规则:
当stone[i]和stone[i-1]的距离大于s*t时
将两者的距离缩减为(stone[i]-stone[i-1)%s+s*t
这里只看走s步的化(也可以走t步)
如果上一个石子的位置记为0,则把stone[i]和stone[i-1]之间可以通过k*s到达的位置都消去了,留下了(stone[i]-stone[i-1]%t的距离,再加上一个从0一定可达的位置:s*t
*/
int main(int argc, char *argv[]) {
cin>>L;
cin>>s>>t>>m;
for(int i=0; i<m; i++){
cin>>stone[i];
}
sort(stone, stone+m);
int identify = 0;
/*
这里我一开始犯了一个致命的错误,就是每次更改距离后,就把石子的坐标更改了,导致后续石子之间的距离发生改变。
所以这里用identify暂存每次更改位置后的石子坐标,stone[]是一定不能改变的。
*/
if(stone[0] > s*t){
identify += stone[0]%s+s*t;
}
else{
identify += stone[0];
}
bridge[identify] = 1;
for(int i=1; i<m; i++){
if(stone[i]-stone[i-1]>s*t){//离散化处理
identify += (stone[i]-stone[i-1])%s+s*t;
}
else{
identify += stone[i]-stone[i-1];
}
bridge[identify] = 1;
}
/*
for(int i=0; i<=10; i++){
cout<<bridge[i]<<' ';
}
cout<<endl;
*/
if(L-stone[m-1] > s*t){
L = identify + (L-stone[m-1])%s+s*t;
}
else{
L = identify + L-stone[m-1];
}
//memset(dp, 0, sizeof(dp));
//dp[0] = 0;
for(int i=1; i<s; i++){
dp[i] = 1e9;
}
for(int i=s; i<=L-1+t; i++){
dp[i] = 1e9;
for(int j=i-t; j<=i-s; j++){
if(j >= 0)
dp[i] = min(dp[i], dp[j]+bridge[i]);
}
//cout<<dp[i]<<' ';
}
//cout<<endl;
int res = 1e9;
for(int i=L; i<=L-1+t; i++){
res = min(res, dp[i]);
}
cout<<res<<endl;
return 0;
}