CF374C Inna and Dima 题解

CF374C Inna and Dima 题解

题目链接:CF374C Inna and Dima

题意

Inna和Dima在商店买了一张 n * m 的桌子,桌子的每一个单元格上都有一个字符,字符集为(“D”,“I”,“M”,“A”)。

Inna实在是太爱Dima了,所以她想在桌子上找出一条最长的路线,使得这条路线中包含尽可能多的Dima的名字(有序,即必须是连续的DIMA)。

Inna的路线选取方式会遵循以下原则:

1.一开始,Inna会在桌子上找到所有的"D",把他们作为起点。

2.Inna会在当前格子的周围四个相邻的格子中选取一个格子,她会从"D"走到"I",从"I"走到"M",从"M"走到"A"。这样,她就认为自己走完了一次Dima的名字。

3.Inna每走完一个格子,就会在该格子四周相邻的四个格子中选一个走,即上下左右四个方向,(当然,她不能走出这张桌子)。Inna从不跳过一个字母。因此,从字母"D"开始,她总是走到字母"I",从字母"I"开始,她总是走到字母"M",从字母"M"开始,她总是走到字母"A",从字母"A"开始,她总是走到字母"D"。

因为桌子的不同,Inna能走的Dima的名字的次数也不同,有时她可以走有限次,有时她可以走无限次,有时她甚至不能走完一次Dima的名字。

现在,她想知道她能否至少走完一次Dima的名字。若可以,她最多能走多少次或者她能否走无限次?

纯记忆化搜索

从每个D都跑一下

对于无限的情况,

只要判断下一个可行格子是不是已经visited了

注意记忆化搜索使用dis数组更新答案

不是靠每次dfs的step

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define N (int)(1e3+15)
int n,m,ans;
char a[N][N];
int dx[5]={1,-1,0,0};
int dy[5]={0,0,1,-1};
int vis[N][N],dis[N][N];
bool safe(int x,int y)
{return 1<=x&&x<=n&&1<=y&&y<=m;}
void dfs(int x,int y)
{
    if(dis[x][y])return;
    vis[x][y]=1;
    dis[x][y]=1;
    for(int k=0; k<4; k++)
    {
        int tx=x+dx[k];
        int ty=y+dy[k];
        if(!safe(tx,ty))continue;
        if(!(a[x][y]=='D'&&a[tx][ty]=='I'||
           a[x][y]=='I'&&a[tx][ty]=='M'||
           a[x][y]=='M'&&a[tx][ty]=='A'||
           a[x][y]=='A'&&a[tx][ty]=='D'))continue;
        if(vis[tx][ty]){cout << "Poor Inna!";exit(0);}
        dfs(tx,ty);
        dis[x][y]=max(dis[x][y],dis[tx][ty]+1);
    }
    vis[x][y]=0;
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    cin >> n >> m;
    for(int i=1; i<=n; i++)
        cin >> a[i]+1;
    for(int i=1; i<=n; i++)
        for(int j=1; j<=m; j++)
        {
            if(a[i][j]=='D'&&!vis[i][j])
            dfs(i,j),ans=max(ans,dis[i][j]);
        }
    ans/=4;
    if(ans==0)cout << "Poor Dima!";
    else cout << ans;
    return 0;
}

转载请说明出处

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值