瑰丽华尔兹--单调队列

看到这道题,的标签

[我csdn的博客]
(https://blog.csdn.net/qq_42421714/article/details/84963779)

我洛谷的博客
说明啊,它可以用单调队列

易推出

dp[x][y][t] = max(dp[x`][y`][t - 1] + 1,dp[x][y][t]);

然后看一下数据范围???
n,m≤200,K≤200,T≤40000
o(n^3)
显然,TLE
然后老师讲了优化方案
T可以换成K
因为任一区间时间内,都只向一个方向走
。。。
然后就可以得到转移方程

dp[x][y][k] = max(dp[x][y][k],dp[x1][ y1][k-1] + Abs(x - x1) + Abs(y - y2));`
x1 y2 表示在x,y的前提下,dp[x1][y1][k - 1] +  Abs(x - x1) + Abs(y - y2))的值最大(在范围内)
'o(n^3)'
等等,时间复杂度貌似没减

就是我们的单调队列神奇登场的时候了
优化最内层循环

思路

滚动优化

dp[x][y][k] 空间复杂度不小
可以发现
dp[x][y][k] 只跟上一次(dp[x][y][k - 1])有关且满足x,y是单调递增或递减的
滚动优化一下

函数优化

4个方向

相信没有人会实诚de用4个if一一处理

所以我们用一个函数
传进去的 必须要有 限制·对应的哪种方向(用数组存一下向迷宫中的四个方向)·当前起点

单调队列

单调队列中的元素不仅要看它自身的值,还要看。val + 它到当前点的距离(在移动范围内)
哪如何实现了
它到当前点的距离可以

Abs(x - q[Index].x) + Abs(y - q[Index].y)

放入队列时我是这样搞的

while(tail >= head&&dp[x][y] > q[tail].val + M(tail))
				tail--;

但我们如何保证循环结束后取出来的就是最大值?(M()宏定义,详见code)
每个元素都是这样放进去的
那么假设队列q={1,2,3}(都是val值)
在枚举点时,每次距离都要加一
1 + 1 = 2
2 + 1 = 3
3 + 1 = 4
q = {1,2,3}
顺序没有发生改变

注意

由于滚动优化后了,处理一个点时只能先放入单调队列

再取出当前最大值

还有X,是不能走的,遇到就重新清一下队列(把Head = 1,tail = 0)

code

#include <cstdio>
#include <cstring>
#define M(Index) Abs(x - q[Index].x) + Abs(y - q[Index].y)
using namespace std;
const int MAXN = 202;
bool Map[MAXN][MAXN];
int n,m,dp[MAXN][MAXN],ans;
int dir[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};
class T
{
	public:
		int val;
		int x,y;
};
template<typename TT>
inline TT Max(TT a,TT b) {if(a > b) return a;return b;}
template<typename TT>
inline TT Abs(TT a) {if(a < 0) return -a;return a;}
inline void Dp(int x,int y,int con,int s)
{
	s--;
	T q[MAXN];
	int head = 1,tail = 0;
	for(;x <= n&&x > 0&&y <= m&&y > 0;x += dir[s][0],y += dir[s][1])
		if(Map[x][y] == 0)
			head = 1,tail = 0;
		else {
		    while(tail >= head&&dp[x][y] > q[tail].val + M(tail))
				tail--;
			tail++;
			q[tail].val = dp[x][y];
			q[tail].x = x;
			q[tail].y = y;
			while(head <= tail&&(Abs(x - q[head].x) > con||Abs(y - q[head].y) > con))
				head++;
            dp[x][y] = Max(dp[x][y],q[head].val + M(head));
            ans = Max(ans,dp[x][y]);
		}
}
int main()
{
    int x,y,k,i,j;
    scanf("%d%d%d%d%d",&n,&m,&x,&y,&k);
    char a;
    for(i = 1;i <= n;i++)
    {
        getchar();
        for(j = 1;j <= m;j++)
        {
            scanf("%c",&a);
            if(a == '.')
                Map[i][j] = 1;
        }
    }
    memset(dp,-0x7f7f7f,sizeof(dp));
    dp[x][y] = 0;
    for(i = 1;i <= k;i++)
    {
        int s,t,d,con;
        scanf("%d%d%d",&s,&t,&d);
        con = t - s + 1;
        if(d == 1) for(j = 1;j <= m;j++) Dp(n,j,con,1);
        if(d == 2) for(j = 1;j <= m;j++) Dp(1,j,con,2);
        if(d == 3) for(j = 1;j <= n;j++) Dp(j,m,con,3);
        if(d == 4) for(j = 1;j <= n;j++) Dp(j,1,con,4);
    }
    printf("%d",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/resftlmuttmotw/p/11323317.html