返回顶部

Contest 2050 and Codeforces Round #718 (Div. 1 + Div. 2) D. Explorer Space (记忆化搜索)

  • 题意:有一个\(n\)x\(m\)的矩阵,相邻点之间都存在边权,每次可以移动到相邻点,问你每个点移动\(k\)次后并回到该点的最短边权和.

  • 题解:如果\(k\)是奇数的话,一定不能走回到自己,因为线段来回来走两次或走一个矩阵,他们的边长和都是偶数.\(dp[i][j][k]\)表示点\((i,j)\)\(k\)次后回到自己的最短边权和,很明显这个状态我们确定后就不会在修改他了,那么可以直接记忆化搜索.

  • 代码:

    #include <bits/stdc++.h>
    #define ll long long
    #define fi first
    #define se second
    #define pb push_back
    #define me memset
    #define rep(a,b,c) for(int a=b;a<=c;++a)
    #define per(a,b,c) for(int a=b;a>=c;--a)
    const int N = 1e6 + 10;
    const int mod = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    using namespace std;
    typedef pair<int,int> PII;
    typedef pair<ll,ll> PLL;
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
     
    int n,m,k;
    int row[505][505],col[505][505];
    int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};
    ll dp[505][505][25];
     
    ll dfs(int x,int y,int cnt){
    	if(cnt==0) return 0;
    	if(dp[x][y][cnt]) return dp[x][y][cnt];
    	ll res=1e18;
    	if(x!=1) res=min(res,dfs(x-1,y,cnt-1)+col[x-1][y]);
    	if(x!=n) res=min(res,dfs(x+1,y,cnt-1)+col[x][y]);
    	if(y!=1) res=min(res,dfs(x,y-1,cnt-1)+row[x][y-1]);
    	if(y!=m) res=min(res,dfs(x,y+1,cnt-1)+row[x][y]);
    	return dp[x][y][cnt]=res;
    }
     
    int main() {
        ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    	cin>>n>>m>>k;
    	
    	rep(i,1,n){
    		rep(j,1,m-1){
    			cin>>row[i][j];
    		}
    	}
     
    	rep(i,1,n-1){
    		rep(j,1,m){
    			cin>>col[i][j];
    		}
    	}
    	
    	if(k&1){
    		rep(i,1,n){
    			rep(j,1,m){
    				cout<<-1<<' ';
    			}
    			cout<<'\n';
    		}
    	}
    	else{
    		rep(i,1,n){
    			rep(j,1,m){
    				cout<<dfs(i,j,k/2)*2<<' ';
    			}
    			cout<<'\n';
    		}
    	}
     
        return 0;
    }
    
posted @ 2021-04-26 20:11  _Kolibri  阅读(46)  评论(0)    收藏  举报