YunYan

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

题意:一个n*m的矩阵,每一个位置都有一定的高度,要求从(1,1)走到(n,m)并且每次移动只能向下或者向右移动,并且要求只能向比自己高度高1的位置移动。定义一个操作:执行一次可以使得任意一个格子的额高度减一,问从1,1到n,m操作的最少次数。

题解:首先一定会有一个格子的高度保持不变,设h(i,j)为格子(i,j)的高度。如果说格子在移动的过程中,格子i,j的高度不减少,那么(1,1)的高度一定是h(i,j)-i-j+2。所以可以枚举(1,1)的高度,然后如果(1,1)的高度确定了,那么整个矩阵每个格子的高度也就确定了,然后直接dp就可以了。

code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=100+7;
const ll INF=1e18+7; 
ll arr[N][N];
vector<ll >ve;
ll dp[N][N];
map<ll,bool>mp;
void solve(){
    ll n,m;
    mp.clear();
    ve.clear();
    cin>>n>>m;
    for(ll i=1;i<=n;i++){
        for(ll j=1;j<=m;j++){
            cin>>arr[i][j];
            ve.push_back(arr[i][j]-i-j+2);
        }
    }
    ll ans=INF;
    for(ll i=0;i<ve.size();i++){ 
        if(mp[ve[i]]) continue ;
        mp[ve[i]]=1;
        if(arr[1][1]<ve[i]) continue ;
        
        for(ll j=0;j<=n;j++){
            for(ll k=0;k<=m;k++){
                dp[j][k]=INF;
            }
        }
        dp[1][1]=arr[1][1]-ve[i]; 
        for(ll j=1;j<=n;j++){
            for(ll k=1;k<=m;k++){ 
                if(arr[j][k]-j-k+2>=ve[i]){
                    dp[j][k]=min(dp[j][k],min(dp[j][k-1],dp[j-1][k])+arr[j][k]-j-k+2-ve[i]);
                }
            }
        } 
        ans=min(ans,dp[n][m]);
    }
    cout<<ans<<endl;
}
int main(){
    ll t;
    cin>>t;
    while(t--) solve();
    return 0;
}

 

posted on 2020-05-22 20:29  Target--fly  阅读(271)  评论(0编辑  收藏  举报