[DP/记忆化搜索] HDU 1078

来源:互联网 发布:仁霸玻璃优化软件 编辑:程序博客网 时间:2024/06/07 20:28

题意

给定一幅图,每个点有一定权值,现在有一只老鼠在起始点(0,0),他能水平或者垂直移动1~k格之后,停在某点并获得权值,而且每次移动后所在的点,都要比刚离开的那个点的权值更大,求最多能获得多少权值。

思路

开始用bottom - up 的 dp做的,当前的最小是来自四个方向的最小,但出现的问题就是因为是按照从左到右,从上到下的顺序访问的,每个点可能更新的时候周围不是最优,解决的方法是按照值的大小顺序访问,就能保证正确。

很多人用的是记忆化搜索,也就是top-down(memoized)的dp,第一次发现这两个的区别,memoized是从源开始找到四周不会再更新的点,再返回向上。搜索的顺序直接就保证了最优。

记忆化搜索还是搜索,从一条路通到底那种,通许多次而已,而dp只是找每个i,j所代表的最大的权值,他的顺序是死的,只是从两个for循环按部就班的找,所以他的路径是死的,一开始这题跟hdu2571一样,那题只能是往有往下走,不能回头,而这题,是四个方向都可以走,是一个“搜索”,所以要用记忆化搜索。

记忆化搜索:这里的dp代表的是从后来所有点一路走来的最大权值,先不断递归,走到不能走了,就要返回,返回值是 dp[x][y]+a[x][y],然后回到上一层递归,继续for循环,再到走不动。。。。然后取max的最大值,这时候dp【x】【y】就已经是最优解了,以后遇到他直接返回就行;回溯完了dp【0】【0】就是从0,0走的最大值;

代码
bottom-up

#include <algorithm>#include <cstdio>#include <cstring>#include <iostream>#define N 105#define INF 0x7f7f7f7fusing namespace std;int n, k, cnt;int val[ N ][ N ];int dp[ N ][ N ];struct Node {    int x, y;    int v;    bool operator< ( const Node n ) const { return v < n.v; }} node[ N * N ];bool path ( int a, int b, int x, int y ) {    if ( a < 0 || a >= n || b < 0 || b >= n )        return false;    if ( val[ a ][ b ] >= val[ x ][ y ] )        return false;    if ( !dp[ a ][ b ] )        return false;    return true;}int LIS () {    int mx = 0;    memset ( dp, 0, sizeof ( dp ) );    dp[ 0 ][ 0 ] = val[ 0 ][ 0 ];    // for ( int x = 0; x < n; ++x ) {    //    for ( int y = 0; y < n; ++y ) {    for ( int p = 0; p < cnt; ++p ) {        int x = node[ p ].x;        int y = node[ p ].y;        // 走i步        for ( int i = 1; i <= k; ++i ) {            if ( path ( x - i, y, x, y ) )                dp[ x ][ y ] = max ( dp[ x ][ y ], dp[ x - i ][ y ] + val[ x ][ y ] );            if ( path ( x + i, y, x, y ) )                dp[ x ][ y ] = max ( dp[ x ][ y ], dp[ x + i ][ y ] + val[ x ][ y ] );            if ( path ( x, y - i, x, y ) )                dp[ x ][ y ] = max ( dp[ x ][ y ], dp[ x ][ y - i ] + val[ x ][ y ] );            if ( path ( x, y + i, x, y ) )                dp[ x ][ y ] = max ( dp[ x ][ y ], dp[ x ][ y + i ] + val[ x ][ y ] );        }        if ( mx < dp[ x ][ y ] )            mx = dp[ x ][ y ];    }    return mx;}int main () {    while ( ~scanf ( "%d%d", &n, &k ) && n != -1 && k != -1 ) {        cnt = 0;        for ( int i = 0; i < n; ++i )            for ( int j = 0; j < n; ++j ) {                scanf ( "%d", &val[ i ][ j ] );                node[ cnt ].x = i;                node[ cnt ].y = j;                node[ cnt++ ].v = val[ i ][ j ];            }        sort ( node, node + cnt );        int sol = LIS ();        printf ( "%d\n", sol );    }    return 0;}

top-down

#include <algorithm>#include <cstdio>#include <cstring>#include <iostream>#define N 105#define INF 0x7f7f7f7fusing namespace std;int n, k;int val[ N ][ N ];int dp[ N ][ N ];int dir[ 4 ][ 2 ] = {1, 0, 0, 1, -1, 0, 0, -1};//下一个的坐标,当前的坐标bool path ( int a, int b, int x, int y ) {    if ( a < n && b < n && a >= 0 && b >= 0 && val[ a ][ b ] > val[ x ][ y ] )        return true;    return false;}int dfs ( int x, int y ) {    if ( dp[ x ][ y ] )        return dp[ x ][ y ];    int ans = 0;    for ( int j = 1; j <= k; ++j )        for ( int i = 0; i < 4; ++i ) {            int xx = x + j * dir[ i ][ 0 ];            int yy = y + j * dir[ i ][ 1 ];            if ( path ( xx, yy, x, y ) )                ans = max ( ans, dfs ( xx, yy ) );        }    return dp[ x ][ y ] = ans + val[ x ][ y ];}int main () {    while ( ~scanf ( "%d%d", &n, &k ) ) {        if ( n == -1 && k == -1 )            break;        for ( int i = 0; i < n; i++ )            for ( int j = 0; j < n; j++ )                scanf ( "%d", &val[ i ][ j ] );        memset ( dp, 0, sizeof ( dp ) );        printf ( "%d\n", dfs ( 0, 0 ) );    }    return 0;}
原创粉丝点击