这道题的动态规划部分还比较直观:
每次只有两个决策:向左走或者向右走。根据这个可以设计出状态:d(i,j,k)表示区间 [i,j] 已经被修复,目前处于最左端(k=0)或最右端(k=1)。
另外, c 值的总和是固定的,不论决策如何,最终都是一样的。因此不用加入状态转移。不过最后不要忘了加上它;
因此只用考虑 delta 就可以了。每次转移的代价就是区间 [i,j] 以外的所有结点的 delta 值乘以机器人移动所需时间。状态转移方程则是 d(i,j) = min( d(i-1, j)+cost1, d(i, j+1)+cost2)
但是有不少值得重视的细节:
1、dp数组不能每次全部置零,会TLE。解决办法是用一个vis数组标记
2、vis数组也不能每次置零,也会TLE。解决办法是用kase来充当标记
3、%.0f会自动四舍五入。需用floor截取整数部分
4、求一个连续区间的和(delta的和),自然应该用前缀和。
5、可以把起始位置当成一个待修复的结点,c和delta设为0。这样就不用在最后分类讨论了
6、对于一个结构体的数组,读取数据的时候直接用scanf("%d",&s[i].x),比读到一个临时变量然后调用构造函数好。
Run Time: 0.429s
#define UVa "LT9-21.1336.cpp" //Fixing the Great Wall
char fileIn[30] = UVa, fileOut[30] = UVa;
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cmath>
using namespace std;
struct Wall {
int x;
double c, d;
bool operator < (const Wall& w2) const {
return x < w2.x;
}
};
//Global Variables. Reset upon Each Case!
const int maxn = 1000 + 10, LEFT = 0, RIGHT = 1;
const double INF = 1e30;
int n, v, sx;
Wall walls[maxn];
double pref_d[maxn];
double sumc;
double d[maxn][maxn][2];
int vis[maxn][maxn][2];
int kase = 0;
/
double cost(int l, int r, int s, int t) {
double result = 0.0;
double sumd = pref_d[n] - (pref_d[r] - pref_d[l] + walls[l].d);
int dist = abs(walls[s].x - walls[t].x);
double tm = (double)dist / (double)v;
result = sumd*tm;
return result;
}
double dp(int l, int r, int k) {
if(l == 0 && r == n) return 0;
double& ans = d[l][r][k];
if(vis[l][r][k] == kase) return ans;
vis[l][r][k] = kase;
ans = INF;
double s = (k==LEFT)?l:r;
if(l > 0) //go left
ans = min(ans, dp(l-1, r, LEFT) + cost(l, r, s, l-1));
if(r < n) //go right
ans = min(ans, dp(l, r+1, RIGHT) + cost(l, r, s, r+1));
return ans;
}
int main() {
memset(vis, 0, sizeof(vis));
while(scanf("%d%d%d", &n, &v, &sx) == 3 && n) {
kase ++;
walls[0].x = sx; walls[0].c = walls[0].d = 0;
int sindex;
sumc = 0;
for(int i = 1; i < n+1; i ++) {
scanf("%d%lf%lf", &walls[i].x, &walls[i].c, &walls[i].d);
sumc += walls[i].c;
}
sort(walls, walls + n + 1);
for(int i = 0; i < n+1; i ++) {
if(walls[i].x == sx) sindex = i;
pref_d[i] = walls[i].d;
if(i) pref_d[i] += pref_d[i-1];
}
printf("%.0f\n", floor(dp(sindex, sindex, LEFT)+(double)sumc));
}
return 0;
}