Codeforces Round #642 (Div. 3) F. Decreasing Heights (dp)

F. Decreasing Heights

题意

给定一个n*m的地图,地图中每一个格子都有一个高度,要你从[1,1]走到[n,m],你只能向下或者向右走,同时,你要去的那个格子里的高度必须比当前格子的高度高1。你可以在走之前执行任意数量的一种操作:选择任意一个格子,使它的高度减一。问从[1,1]走到[n,m]所需执行的最少操作次数是多少。

思路

如果我们能确定[1,1]处的值,那么直接dp就好,关键在于[1,1]处的值是变化的,所以我们想办法枚举[1,1]处的值。
如果我们令[1,1]处的值为0,假设任一条路都能到[n,m],则此时地图应该如下图所示。
Codeforces Round #642 (Div. 3) F. Decreasing Heights (dp)_第1张图片
然后我们让地图每一个位置减去表中的值,这样的话,原来的要走向比自己高度高1,就变成了要走向和自己高度相同。
之后,我们不重复的将这个地图中数枚举为[1,1]处的值,进行 dp 求从左上角到右下角最小的权值和。在所有值中取最小即可。

代码

#include 
 
using namespace std;
 
int t;
int n,m;
long long a[105][105];
 
int main()
{
    cin >> t;
    while(t--)
    {
        cin >> n >> m;
        for(int i = 1; i <= n; ++i){
            for(int j = 1; j <= m; ++j){
                cin >> a[i][j];
                a[i][j] -= (i+j-2);//减去表中的值
            }
        }
//        for(int i = 1; i <= n; ++i){
//            for(int j = 1; j <= m; ++j){
//                cout << a[i][j] << " ";
//            }
//            cout << endl;
//        }
        long long ans = 1e18;
        unordered_map<long long,int> book;//标记
        for(int x = 1; x <= n; ++x){
            for(int y = 1; y <= m; ++y){
                if(book[a[x][y]])
                    continue;
                book[a[x][y]] = 1;
                long long dp[105][105];
                for(int i = 1; i <= 100; ++i)
                    for(int j = 1; j <= 100; ++j)
                        dp[i][j] = 1e18;
                dp[1][1] = a[1][1]-a[x][y];
                if(dp[1][1]<0)
                    continue;
                for(int i = 1; i <= n; ++i){
                    for(int j = 1; j <= m; ++j){
                        if(a[i+1][j]-a[x][y]>=0)
                            dp[i+1][j] = min(dp[i+1][j],dp[i][j]+a[i+1][j]-a[x][y]);
                        if(a[i][j+1]-a[x][y]>=0)
                            dp[i][j+1] = min(dp[i][j+1],dp[i][j]+a[i][j+1]-a[x][y]);
                    }
                }
//                for(int i = 1; i <= n; ++i){
//                    for(int j = 1; j <= m; ++j){
//                        cout << dp[i][j] << " ";
//                    }
//                    cout << endl;
//                }
                ans = min(ans,dp[n][m]);
            }
        }
        cout << ans << endl;
    }
    return 0;
}

你可能感兴趣的:(Codeforces)