现在的位置: 首页 > 综合 > 正文

UVa #1336 Fixing the Great Wall (例题9-21)

2018年10月14日 ⁄ 综合 ⁄ 共 1878字 ⁄ 字号 评论关闭

这道题的动态规划部分还比较直观:

每次只有两个决策:向左走或者向右走。根据这个可以设计出状态: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;
}

抱歉!评论已关闭.