hdu4362 dp + 单调队列优化

5 篇文章 0 订阅

dp转移方程很容易想 dp[i][j] = min{dp[i - 1][k] + abs(pos[i][j] -pos[i - 1][j]) + cost[i][j]}

n行m列 每次转移扫描m次 共n*m*m 为O(10^7)    1500ms,可以暴力一试。姿势不对就会TLE

其实加上个内联函数求绝对值,同时赋值时候不使用min(a, b)  用G++交 就可以水过


正解是:因为每个转移都是从上一层所有的状态开始转移,将上一层的状态根据pos排序

对当前状态的pos进行讨论,其坐标轴左边的点dp[i][j] = dp[i - 1][k] - pos][i - 1][k]+ pos[i][j]  + cost[i][j]

          对其坐标轴右边的点便是 dp[i][j] = dp[i - 1][k]+ pos][i - 1][k]  - pos[i][j] + cost[i][j],       pos][i][j] cost[i][j]是常数。

 维护一个lans[i],表示上一层0 ~ i位置的dp[i - 1][k] - pos][i - 1][k]最小值;   和一个rans[i],表示上一层i ~ (m - 1)位置的dp[i - 1][k] + pos][i - 1][k]最小值

二分当前状态的pos,若为p,比较左边lans[p - 1]与右边lans[p]的最小值即可


//#pragma comment(linker, "/STACK:102400000,102400000")
//HEAD
#include <cstdio>
#include <cstring>
#include <vector>
#include <iostream>
#include <algorithm>

#include <queue>
#include <string>
#include <set>
#include <stack>
#include <map>
#include <cmath>
#include <cstdlib>

using namespace std;
//LOOP
#define FE(i, a, b) for(int i = (a); i <= (b); ++i)
#define FED(i, b, a) for(int i = (b); i>= (a); --i)
#define REP(i, N) for(int i = 0; i < (N); ++i)
#define CLR(A,value) memset(A,value,sizeof(A))
//STL
#define PB push_back
//INPUT
#define RI(n) scanf("%d", &n)
#define RII(n, m) scanf("%d%d", &n, &m)
#define RIII(n, m, k) scanf("%d%d%d", &n, &m, &k)
#define RS(s) scanf("%s", s)

#define FF(i, a, b) for(int i = (a); i < (b); ++i)
#define FD(i, b, a) for(int i = (b) - 1; i >= (a); --i)
#define CPY(a, b) memcpy(a, b, sizeof(a))
#define FC(it, c) for(__typeof((c).begin()) it = (c).begin(); it != (c).end(); it++)
#define EQ(a, b) (fabs((a) - (b)) <= 1e-10)
#define ALL(c) (c).begin(), (c).end()
#define SZ(V) (int)V.size()
#define RIV(n, m, k, p) scanf("%d%d%d%d", &n, &m, &k, &p)
#define RV(n, m, k, p, q) scanf("%d%d%d%d%d", &n, &m, &k, &p, &q)
#define WI(n) printf("%d\n", n)
#define WS(s) printf("%s\n", s)
#define sqr(x) x * x
typedef long long LL;
typedef vector <int> VI;
typedef unsigned long long ULL;
const double eps = 1e-10;
const LL MOD = 1e9 + 7;

using namespace std;

const int maxn = 1010;
const int INF = 0x3f3f3f3f;

int dp[55][maxn], n, m, x;
int lm[maxn], rm[maxn], lans[maxn], rans[maxn];

struct Node{
    int pos, cost;
    int lval, rval;
    bool operator <(const Node& a) const
    {
        return pos < a.pos;
    }
}a[55][maxn];

void init(int u)
{

    REP(j, m)
    {
        a[u][j].lval = dp[u][j] - a[u][j].pos;
        a[u][j].rval = dp[u][j] + a[u][j].pos;
    }
    sort(a[u], a[u] + m);
    CLR(lm, INF), CLR(rm, INF);
    int s = 0, e = 0;
    lans[0] = lm[0] = a[u][0].lval, rans[m - 1] = rm[0] = a[u][m - 1].rval;
    FF(j, 1, m)
    {
        Node &v = a[u][j];
        if (v.lval > lm[e])   lm[++e] = v.lval;
        else
        {
            while (e >= 0 && v.lval < lm[e])  --e;
            lm[++e] = v.lval;
        }
        lans[j] = lm[0];
    }
    s = e = 0;
    FED(j, m - 2, 0)
    {
        Node &v = a[u][j];
        if (v.rval > rm[e])   rm[++e] = v.rval;
        else
        {
            while (e >= 0 && v.rval < rm[e])  --e;
            rm[++e] = v.rval;
        }
        rans[j] = rm[0];
    }
}

int main()
{
    int T;
    RI(T);
    while (T--)
    {
        RIII(n, m, x);
        REP(i, n)   REP(j, m)   RI(a[i][j].pos);
        REP(i, n)   REP(j, m)   RI(a[i][j].cost);
        REP(j, m)   dp[0][j] = abs(x - a[0][j].pos) + a[0][j].cost;
        FE(i, 1, n - 1)
        {
            init(i - 1);
            REP(j, m)
            {
                int p = lower_bound(a[i - 1], a[i - 1] + m, a[i][j]) - a[i - 1];
//                cout << "position  "<< p << endl;
                int lmin = INF, rmin = INF;
                if (p) lmin = lans[p - 1] + a[i][j].pos + a[i][j].cost;
                if (p < m)  rmin = rans[p] - a[i][j].pos + a[i][j].cost;
//                cout << "rans[p]:  " << rans[p] << endl;
//                cout << "lmin: " <<lmin << "rmin:  " << rmin << endl;
                dp[i][j] = min(lmin, rmin);
            }
        }
        int ans = INF;
        REP(j, m)   ans = min(dp[n - 1][j], ans);
        cout << ans << endl;
    }
    return 0;
}

这是水过的 1109ms

//#pragma comment(linker, "/STACK:102400000,102400000")
//HEAD
#include <cstdio>
#include <cstring>
#include <vector>
#include <iostream>
#include <algorithm>

#include <queue>
#include <string>
#include <set>
#include <stack>
#include <map>
#include <cmath>
#include <cstdlib>

using namespace std;
//LOOP
#define FE(i, a, b) for(int i = (a); i <= (b); ++i)
#define FED(i, b, a) for(int i = (b); i>= (a); --i)
#define REP(i, N) for(int i = 0; i < (N); ++i)
#define CLR(A,value) memset(A,value,sizeof(A))
//STL
#define PB push_back
//INPUT
#define RI(n) scanf("%d", &n)
#define RII(n, m) scanf("%d%d", &n, &m)
#define RIII(n, m, k) scanf("%d%d%d", &n, &m, &k)
#define RS(s) scanf("%s", s)

#define FF(i, a, b) for(int i = (a); i < (b); ++i)
#define FD(i, b, a) for(int i = (b) - 1; i >= (a); --i)
#define CPY(a, b) memcpy(a, b, sizeof(a))
#define FC(it, c) for(__typeof((c).begin()) it = (c).begin(); it != (c).end(); it++)
#define EQ(a, b) (fabs((a) - (b)) <= 1e-10)
#define ALL(c) (c).begin(), (c).end()
#define SZ(V) (int)V.size()
#define RIV(n, m, k, p) scanf("%d%d%d%d", &n, &m, &k, &p)
#define RV(n, m, k, p, q) scanf("%d%d%d%d%d", &n, &m, &k, &p, &q)
#define WI(n) printf("%d\n", n)
#define WS(s) printf("%s\n", s)
#define sqr(x) x * x
typedef long long LL;
typedef vector <int> VI;
typedef unsigned long long ULL;
const double eps = 1e-10;
const LL MOD = 1e9 + 7;

using namespace std;

const int maxn = 1010;
const int INF = 0x3f3f3f3f;

inline int ABS(int x)   {if (x < 0) return -x; return x; }
int pos[55][maxn], cost[55][maxn];
int dp[55][maxn];

int main()
{
    int T, n, m, x;
    RI(T);
    while (T--)
    {
        RIII(n, m, x);
        REP(i, n)   REP(j, m)   RI(pos[i][j]);
        REP(i, n)   REP(j, m)   RI(cost[i][j]);
        REP(i, m)
            dp[0][i] = ABS(x - pos[0][i]) + cost[0][i];
        FE(i, 1, n - 1)
            REP(j, m)
            {
                int t = INF;
                  REP(k, m)
                {
//                    dp[i][j] = min(dp[i][j], dp[i - 1][k] + ABS(pos[i][j] - pos[i - 1][k]));
                    int x = dp[i - 1][k] + ABS(pos[i][j] - pos[i - 1][k]);
                    if (x < t)
                        t = x;
                }
                dp[i][j] = t + cost[i][j];
            }
        int ans = INF;
        REP(i, m)   ans = min(ans, dp[n - 1][i]);
        WI(ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值