Luogu-P2295 MICE

Posted seanocean

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Luogu-P2295 MICE相关的知识,希望对你有一定的参考价值。

 

题目

题目链接

 技术图片

 

测试得分:  100

 

 

 

主要算法 :  记忆化搜索,动态规划

 

 

题干:

  有后效性DP?

 分析

  伪记忆化搜索:

    考虑起点的特殊情况,预先处理
    Dfs搜出答案,每一次路径看到的老鼠,加上老鼠数目,把看到的老鼠数目所在点的老鼠删除掉
    记得回溯最终得分40分

  代码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define FORa(i,s,e) for(int i=s;i<=e;i++)
#define FORs(i,s,e) for(int i=s;i>=e;i--)
#define gc getchar()//pa==pb&&(pb=(pa=buf)+fread(buf,1,100000,stdin),stdin)?EOF:*pa++
#define File(name) freopen(name".in","r",stdin);freopen(name".out","w",stdout);

using namespace std;
char buf[100000],*pa,*pb;
inline int read();

const int N=1100,M=1100,INF=2147483647;
int n,m,a[N+1][M+1],s[N+1][M+1],f[N+1][M+1][2];
int ans=INF,mx[]=0,1,-1,0,my[]=1,0,0,-1;

inline int min(int fa,int fb)return fa<fb?fa:fb;
void Init()

    n=read(),m=read();
    FORa(i,1,n) FORa(j,1,m) a[i][j]=read();

void Dfs(int x,int y,int cnt)

    
    if(s[x][y]<cnt||cnt>=ans) return;
    s[x][y]=cnt;
    if(x==n&&y==m)
    
        ans=min(cnt,ans);
        return;
    
    int fx,fy,p[4];
    FORa(i,0,1)
    
        fx=x+mx[i],fy=y+my[i];
        if(fx<=n&&fy<=m)
        
            FORa(k,0,3) p[k]=a[fx+mx[k]][fy+my[k]],a[fx+mx[k]][fy+my[k]]=0;
            Dfs(fx,fy,cnt+p[0]+p[1]+p[2]+p[3]);            
            FORa(k,0,3) a[fx+mx[k]][fy+my[k]]=p[k];
            
    

void Solve_BL()

    memset(s,127,sizeof(s));
    int cnt=a[1][1]+a[1][2]+a[2][1];
    a[1][2]=a[2][1]=a[1][1]=0;
    Dfs(1,1,cnt);
    printf("%d",ans);

int main()

    Init();
    Solve_BL();
    return 0;

inline int read()

    register char c(gc);register int f(1),x(0);
    while(c<0||c>9) f=c==-?-1:1,c=gc;
    while(c>=0&&c<=9) x=(x<<1)+(x<<3)+(c^48),c=gc;
    return x*f;

/*
5 5
86 19 26 18 92 
25 67 69 28 83 
54 56 7 5 93 
63 33 8 66 91 
68 74 56 92 90 */

 

  100分DP

    定义:
      a[i][j]表示格子(i,j)中老鼠的数量。
      f[i][j][0]表示当前小象位于格子(i,j)且上一个位置是(i-1,j)所看见的老鼠的最少数量。
      f[i][j][1]表示当前小象位于格子(i,j)且上一个位置是(i,j-1)所看见的老鼠的最少数量
    我们可以得到转移方程:
      f[i][j][0]=min(f[i-1][j][0]+a[i][j-1],f[i-1][j][1])+a[i+1][j]+a[i][j+1]
      f[i][j][1]=min(f[i][j-1][0],f[i][j-1][1]+a[i-1][j])+a[i+1][j]+a[i][j+1]
    最后答案为 min(f[n][m][0],f[n][m][1])。 复杂度:O(N*M)。 

 

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define FORa(i,s,e) for(int i=s;i<=e;i++)
#define FORs(i,s,e) for(int i=s;i>=e;i--)
#define gc getchar()//pa==pb&&(pb=(pa=buf)+fread(buf,1,100000,stdin),stdin)?EOF:*pa++
#define File(name) freopen(name".in","r",stdin);freopen(name".out","w",stdout);

using namespace std;
char buf[100000],*pa,*pb;
inline int read();

const int N=1100,M=1100;
int n,m,f[N+1][M+1][2],a[N+1][M+1];

inline int min(int fa,int fb)return fa<fb?fa:fb;
void Solve_Dp()

    memset(f,63,sizeof(f));
    n=read(),m=read();
    FORa(i,1,n) FORa(j,1,m) a[i][j]=read(); 
    f[1][1][0]=f[1][1][1]=a[1][1]+a[1][2]+a[2][1];
    FORa(i,1,n)
        FORa(j,1,m)
            if(i*j!=1)
            
                f[i][j][0]=min(f[i][j-1][0]+a[i-1][j],f[i][j-1][1])+a[i+1][j]+a[i][j+1];
                f[i][j][1]=min(f[i-1][j][1]+a[i][j-1],f[i-1][j][0])+a[i+1][j]+a[i][j+1];
            
    printf("%d\\n",min(f[n][m][0],f[n][m][1]));

int main()

    File("lemouse");
    Solve_Dp();
    return 0;

inline int read()

    register char c(gc);register int f(1),x(0);
    while(c<0||c>9) f=c==-?-1:1,c=gc;
    while(c>=0&&c<=9) x=(x<<1)+(x<<3)+(c^48),c=gc;
    return x*f;

/*
5 5
86 19 26 18 92 
25 67 69 28 83 
54 56 7 5 93 
63 33 8 66 91 
68 74 56 92 90 */

 

总结:

   确定动规模型

 

技术图片

以上是关于Luogu-P2295 MICE的主要内容,如果未能解决你的问题,请参考以下文章

Luogu-P2758 编辑距离

Luogu-P1018 乘积最大

Luogu-P1967 货车运输

Luogu-P2324-[SCOI2005]骑士精神

Luogu-P3375 模板KMP字符串匹配

Luogu-P4289-[HAOI2008]移动玩具