【牛客 - 301哈尔滨理工大学软件与微电子学院第八届程序设计竞赛同步赛(高年级)】小乐乐下象棋(记忆化搜索dp,dfs)

版权声明:欢迎学习我的博客,希望ACM的发展越来越好~ https://blog.csdn.net/qq_41289920/article/details/84763563

题干:
 

小乐乐一天天就知道玩,这一天又想玩象棋。
我们都知道马走日。
现在给定一个棋盘,大小是n*m,把棋盘放在第一象限,棋盘的左下角是(0,0),右上角是(n - 1, m - 1);
小乐乐想知道,一个马从左下角(0, 0)开始,走了k步之后,刚好走到右上角(n - 1, m - 1)的方案数。

输入描述:

输入:多组样例输入,每组一行,三个整数n, m, k(1 <= n, m, k <= 200),如题目所示。

输出描述:

输出:输出答案 mod 1000000007

示例1

输入

复制

4 4 2

输出

复制

2

解题报告:

   跪了一晚上发现是因为写成了ty=x+ny[k]了,,,看来是太久不写地图的dfs了、、老毛病又犯了、、难受难受

AC代码1:(记忆化搜索)

  其实也可以直接在main函数中dp[n][m][0]=1,这样在写dfs的时候就不需要特判一下出口了、、总的来说是个不算难的好题、、

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define ll long long
#define pb push_back
#define pm make_pair
#define fi first
#define se second
using namespace std;
const int MAX = 2e5 + 5;
ll dp[205][205][205];
const ll mod = 1000000007;
int n,m,t;
int nx[9] = {-2,-1,1,2,2,1,-1,-2};
int ny[9] = {1,2,2,1,-1,-2,-2,-1};
bool ok(int x,int y) {
	if(x>=1&&x<=n&&y>=1&&y<=m) return 1;
	else return 0;
}
ll dfs(int x,int y,int res) {
	if(x == n && y == m && res == 0) return dp[n][m][res]=1;
	if(res <= 0) return 0;
	if(dp[x][y][res]!=-1) return dp[x][y][res];
	ll sum = 0;
	int tx,ty;
	for(int k = 0; k<8; k++) {
		tx = x + nx[k];
		ty = y + ny[k];
		if(ok(tx,ty) == 0) continue;
		//if(res==0) continue;
		sum += dfs(tx,ty,res-1);
		sum %= mod;
	}
	dp[x][y][res] = sum;
	return sum;
	
}
int main()
{
	while(~scanf("%d%d%d",&n,&m,&t)) {
		memset(dp,-1,sizeof dp);
		printf("%lld\n",dfs(1,1,t)%mod);
	}	
	return 0 ;
 }

其中也有一个细节值得注意,,这样搜索的正确性,,首先因为你表示的状态,体现出了剩余的步数,所以不用怕走过去下一步又走回来这种情况,,因为在状态设计中这属于不同的状态,,所以没事,,再就是不用怕会出现环,,也就是绕一圈状态又绕回来了。。原因就是因为你的dfs都是res-1的操作,所以整个就是一个DAG图,不必要担心会出现未完成值的重复调用。。

AC代码2:(三种直接dp)

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pii pair<int,int>
#define x first
#define y second
#define mp make_pair
//#define debug
const LL mod=1e9+7;
LL f[205][205][205];
int fx[8][2]={1,2,1,-2,2,1,2,-1,-1,-2,-1,2,-2,-1,-2,1};
void B(){
    int n,m,K;
    while(cin>>n>>m>>K){
        memset(f,0,sizeof(f));
        f[1][1][0]=1;
        for(int k=0;k<=K;++k){
        for(int i=1;i<=n;++i){
            for(int j=1;j<=m;++j){
                    if(f[i][j][k]){
                        for(int o=0;o<8;++o){
                            if(i+fx[o][0]>=1 && j+fx[o][1]>=1)
                            (f[i+fx[o][0]][j+fx[o][1]][k+1]+=f[i][j][k])%=mod; 
                        }
                    }
                }
            }
        }
        cout<<f[n][m][K]<<endl;
    }
}
int main(){
    B();
    return 0;
}





#include<bits/stdc++.h>
#define mod 1000000007
using namespace std;
int dp[205][205][205];
int dis[8][2]={2,1,2,-1,-2,1,-2,-1,1,2,1,-2,-1,2,-1,-2};
int main()
{
    int n,m,k;
    while(scanf("%d%d%d",&n,&m,&k)!=EOF)
    {
        memset(dp,0,sizeof(dp));
        dp[1][1][0]=1;
        for(int s=1;s<=k;s++)
            for(int i=1;i<=n;i++)
                for(int j=1;j<=m;j++)
                {
                    int temp=0;
                    for(int h=0;h<8;h++)
                    {
                        int x=i+dis[h][0];int y=j+dis[h][1];
                        if(x>=1&&x<=n&&y>=1&&y<=m)
                        temp+=dp[x][y][s-1],temp%=mod;
                }
                dp[i][j][s]=temp;
    }
    printf("%d\n",dp[n][m][k]);
}
    return 0;
}




#include <bits/stdc++.h>
using namespace std;
int dp[205][205][205];
const int mod=1000000007;
int nex[8][2]={{1,2},{2,1},{-1,-2},{-2,-1},{2,-1},{1,-2},{-1,2},{-2,1}};
int main()
{
    int n,m,d;
    while(~scanf("%d %d %d",&n,&m,&d))
    {
        memset(dp,0,sizeof(dp));
        dp[1][1][0]=1;
        for(int k=1;k<=d;k++){
            for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++){
                for(int s=0;s<8;s++){
                    int x=i+nex[s][0];
                    int y=j+nex[s][1];
                    if(x<1||y<1||x>n||y>m) continue;
                    dp[i][j][k]=(dp[i][j][k]+dp[x][y][k-1])%mod;
                }
            }
        }
        printf("%d\n",dp[n][m][d]);
    }
    return 0;
}

看了dp的代码发现dp好像也不是很难写、、、也不是很难想,,因为这种状态也是符合递推的。。

简单的一个题,,着实又让我对动态规划有了新的理解!!!!

考虑改编:

    改编成一个n*m的方格,但是终点不是右上角的那个[n,m]点,而是新输入的两个点,,这样进行dp,,但是可能有个问题就是可能搜索的范围会大了很多啊。。

猜你喜欢

转载自blog.csdn.net/qq_41289920/article/details/84763563