您的位置:首页 > 其它

【noi2005试题】瑰丽华尔兹 单调队列优化DP

2014-03-31 22:03 459 查看
1A。。。。。。

dp【k】【i】【j】 表示第k段的倾斜之后到达(i,j)处时已经滑动的最长距离

根据倾斜的方向,来进行递推

比如 当向下倾斜时 dp【k】【i】【j】 = max( dp【k-1】【i-k】【j】 +k ) k <= t

这里如果不优化的时间复杂度就变成了 knmn

所以要用单调队列来优化这个决策的时间,优化前为o(n),优化后为o(1)

AC代码如下:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;

struct Node{
int a, b;
int dir;
};

int N, M, K;
int sx, sy;
char maps[210][210];
Node node[2000];
int dp[220][220][220];

void dp_up( int t, int step ){
int q[220], pos[220], head, tail;
for( int j = 1; j <= M; j++ ){
head = 0;
tail = -1;
for( int i = N; i >= 1; i-- ){
if( maps[i][j] == 'x' ){
tail = head - 1;
continue;
}else{
if( dp[step-1][i][j] != -1 ){
while( head <= tail && dp[step-1][i][j] + i > q[tail] ) tail--;
tail++;
q[tail] = dp[step-1][i][j] + i;
pos[tail] = i;
}
}
while( head <= tail && pos[head] - i > t )  head++;
if( head <= tail )  dp[step][i][j] = q[head] - i;
}
}
}

void dp_down( int t, int step ){
int q[220], pos[220], head, tail;
for( int j = 1; j <= M; j++ ){
head = 0;
tail = -1;
for( int i = 1; i <= N; i++ ){
if( maps[i][j] == 'x' ){
tail = head - 1;
continue;
}else{
if( dp[step-1][i][j] != -1 ){
while( head <= tail && dp[step-1][i][j] - i > q[tail] ) tail--;
tail++;
q[tail] = dp[step-1][i][j] - i;
pos[tail] = i;
}
}
while( head <= tail && i - pos[head] > t )  head++;
if( head <= tail )  dp[step][i][j] = q[head] + i;
}
}
}

void dp_left( int t, int step ){
int q[220], pos[220], head, tail;
for( int i = 1; i <= N; i++ ){
head = 0;
tail = -1;
for( int j = M; j >= 1; j-- ){
if( maps[i][j] == 'x' ){
tail = head - 1;
continue;
}else{
if( dp[step-1][i][j] != -1 ){
while( head <= tail && dp[step-1][i][j] + j > q[tail] ) tail--;
tail++;
q[tail] = dp[step-1][i][j] + j;
pos[tail] = j;
}
}
while( head <= tail && pos[head] - j > t )  head++;
if( head <= tail )  dp[step][i][j] = q[head] - j;
}
}
}

void dp_right( int t, int step ){
int q[220], pos[220], head, tail;
for( int i = 1; i <= N; i++ ){
head = 0;
tail = -1;
for( int j = 1; j <= M; j++ ){
if( maps[i][j] == 'x' ){
tail = head - 1;
continue;
}else{
if( dp[step-1][i][j] != -1 ){
while( head <= tail && dp[step-1][i][j] - j > q[tail] ) tail--;
tail++;
q[tail] = dp[step-1][i][j] - j;
pos[tail] = j;
}
}
while( head <= tail && j - pos[head] > t )  head++;
if( head <= tail )  dp[step][i][j] = q[head] + j;
}
}
}

int main(){
while( scanf( "%d%d%d%d%d", &N, &M, &sx, &sy, &K ) != EOF ){
for( int i = 1; i <= N; i++ ){
scanf( "%s", &maps[i][1] );
}
for( int i = 1; i <= K; i++ ){
scanf( "%d%d%d", &node[i].a, &node[i].b, &node[i].dir );
}
memset( dp, -1, sizeof( dp ) );
dp[0][sx][sy] = 0;
for( int i = 1; i <= K; i++ ){
switch( node[i].dir ){
case 1 : dp_up( node[i].b - node[i].a + 1, i );break;
case 2 : dp_down( node[i].b - node[i].a + 1, i );break;
case 3 : dp_left( node[i].b - node[i].a + 1, i );break;
case 4 : dp_right( node[i].b - node[i].a + 1, i );break;
}
}
int ans = -1;
for( int i = 1; i <= N; i++ ){
for( int j = 1; j <= M; j++ ){
ans = max( ans, dp[K][i][j] );
}
}
cout << ans << endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: