P3956 棋盘 dfs和bfs

题目描述

有一个m×m的棋盘,棋盘上每一个格子可能是红色、黄色或没有任何颜色的。你现在要从棋盘的最左上角走到棋盘的最右下角。

任何一个时刻,你所站在的位置必须是有颜色的(不能是无色的), 你只能向上、 下、左、 右四个方向前进。当你从一个格子走向另一个格子时,如果两个格子的颜色相同,那你不需要花费金币;如果不同,则你需要花费 1个金币。

另外, 你可以花费 2 个金币施展魔法让下一个无色格子暂时变为你指定的颜色。但这个魔法不能连续使用, 而且这个魔法的持续时间很短,也就是说,如果你使用了这个魔法,走到了这个暂时有颜色的格子上,你就不能继续使用魔法; 只有当你离开这个位置,走到一个本来就有颜色的格子上的时候,你才能继续使用这个魔法,而当你离开了这个位置(施展魔法使得变为有颜色的格子)时,这个格子恢复为无色。

现在你要从棋盘的最左上角,走到棋盘的最右下角,求花费的最少金币是多少?

输入输出格式

输入格式:

 

第一行包含两个正整数m, n,以一个空格分开,分别代表棋盘的大小,棋盘上有颜色的格子的数量。

接下来的n行,每行三个正整数x, y,c, 分别表示坐标为(x,y)的格子有颜c。

其中c=1 代表黄色,c=0代表红色。 相邻两个数之间用一个空格隔开。 棋盘左上角的坐标为(1, 1),右下角的坐标为( m, m)

棋盘上其余的格子都是无色。保证棋盘的左上角,也就是(1, 1) 一定是有颜色的。

 

输出格式:

 

一个整数,表示花费的金币的最小值,如果无法到达,输出−1。

 

输入输出样例

输入样例#1: 复制

5 7
1 1 0
1 2 0
2 2 1
3 3 1
3 4 0
4 4 1
5 5 0

输出样例#1: 复制

8

输入样例#2: 复制

5 5
1 1 0
1 2 0
2 2 1
3 3 1
5 5 0

输出样例#2: 复制

-1

思路还是比较清楚,dfs或者bfs,但是无论是哪种,必须将所有的穷举到,不能找到结果就退出!

刚开始 我的dfs +剪枝,没有通过最后5个 TLE。

我觉得主要原因是使用了visit数组,标记那些使用过的。这个比较耽误时间。最后看了别人的(见最后),恍然大悟。

#include<stdio.h>
#include<queue>
#include<vector>
#include<iostream>
#include<sstream>
#include<string.h>
#include<map>
#include<set>
#include<cmath>
#include<algorithm>
#include <climits>
using namespace std;
#define N 105
int m,n;
int c[N][N];
int xx[]= { 1,-1,0,0	};
int yy[]= { 0,0,-1,1	};
int nums[N][N];
int imin=INT_MAX;
// 坐标xy, 金币数量, 是否变色 原来颜色, 是否访问
void dfs(int x,int y,int num,int isc,int lsc,vector<bool> vist)
{
    if(x==m&&y==m)
    {
        imin=min(imin,num);
        return;
    }
    if(nums[x][y]<num)
        return;
    else
        nums[x][y]=num;

    //cout<<x<<" ---------- "<<y<<" ---"<<num<<endl;

    for(int i=0; i<4; i++)
    {
        int nx=x+xx[i];
        int ny=y+yy[i];
        if(nx<=0||nx>m||ny<=0||ny>m)
            continue;
        if(vist[(nx-1)*m+ny-1])
            continue;

        vist[(nx-1)*m+ny-1]=true;

        if(c[x][y]==c[nx][ny]&&c[x][y]>=0&&c[nx][ny]>=0)
        {
            dfs(nx,ny,num,0,0,vist);
        } else if(c[x][y]!=c[nx][ny]&&c[x][y]>=0&&c[nx][ny]>=0)
        {
            dfs(nx,ny,num+1,0,0,vist);
        } else if(c[x][y]<0&&c[nx][ny]>=0)
        {
            if(lsc==c[nx][ny])
                dfs(nx,ny,num,0,0,vist);
            else dfs(nx,ny,num+1,0,0,vist);

        } else if(c[x][y]<0&&c[nx][ny]<0)
        {
            continue;
        } else if(c[x][y]>=0&&c[nx][ny]<0)
        {
            dfs(nx,ny,num+2,1,c[x][y],vist);
        }
    }
};
int main()
{
    cin>>m>>n;
    int x,y,tc;
    vector<bool> vist(m*m,0);
    for(int i=1; i<=m; i++)
        for(int j=1; j<=m; j++)
        {
            c[i][j]=-1;
            nums[i][j]=INT_MAX;
        }
    for(int i=0; i<n; i++)
    {
        cin>>x>>y>>tc;
        c[x][y]=tc;
    }
    vist[0]=true;
    dfs(1,1,0,0,0,vist);
    if(imin!=INT_MAX)
        cout<<imin<<endl;
    else
        cout<<-1<<endl;

    return 0;
}

最后5个超时间,我就想使用bfs,顺利通过

#include<stdio.h>
#include<queue>
#include<vector>
#include<iostream>
#include<sstream>
#include<string.h>
#include<map>
#include<set>
#include<cmath>
#include<algorithm>
#include <climits>
using namespace std;
#define N 105
int m,n;
int c[N][N];
int xx[]= {
    1,-1,0,0
};
int yy[]= {
    0,0,-1,1
};
typedef struct
{
    int x;
    int y;
    int num;
    int isc;
    int lsc;
} Node;
Node tp;
int nums[N][N];
int imin=INT_MAX;
queue<Node> qu;

void bfs()
{
    int x,y,num,isc,lsc;
    if(qu.empty()) return;
    tp=qu.front();
    qu.pop();
    x=tp.x;
    y=tp.y;
    isc=tp.isc;
    lsc=tp.lsc;
    num=tp.num;
    if(x==m&&y==m)
    {
        imin=min(imin,num);
        //return;  这里不能使用,否则找到一个结果就退出了 
    }
    //cout<<x<<" ---------- "<<y<<" ---"<<num<<endl;
    for(int i=0; i<4; i++)
    {
        int nx=x+xx[i];
        int ny=y+yy[i];
        int nlsc,nisc,nnum;
        if(nx<=0||nx>m||ny<=0||ny>m)
            continue;

        if(c[x][y]==c[nx][ny]&&c[x][y]>=0&&c[nx][ny]>=0)
        {
            //dfs(nx,ny,num,0,0,vist);
            nlsc=0,nisc=0,nnum=num;
        } else if(c[x][y]!=c[nx][ny]&&c[x][y]>=0&&c[nx][ny]>=0)
        {
            //dfs(nx,ny,num+1,0,0,vist);
            nlsc=0,nisc=0,nnum=num+1;
        } else if(c[x][y]<0&&c[nx][ny]>=0)
        {
            if(lsc==c[nx][ny])
            {   //dfs(nx,ny,num,0,0,vist);
                nlsc=0,nisc=0,nnum=num;
            }
            else
            {
                //dfs(nx,ny,num+1,0,0,vist);
                nlsc=0,nisc=0,nnum=num+1;
            }

        } else if(c[x][y]<0&&c[nx][ny]<0)
        {
            continue;
        } else if(c[x][y]>=0&&c[nx][ny]<0)
        {
            //dfs(nx,ny,num+2,1,c[x][y],vist);
            nlsc=c[x][y],nisc=1,nnum=num+2;

        }

        if(nums[nx][ny]<=nnum)
            continue;
        else
        {
            nums[nx][ny]=nnum;
            tp.x=nx;
            tp.y=ny;
            tp.isc=nisc;
            tp.lsc=nlsc;
            tp.num=nnum;
            qu.push(tp);
        }
    }
    bfs();
};
int main()
{
    cin>>m>>n;
    int x,y,tc;
    vector<bool> vist(m*m,0);
    for(int i=1; i<=m; i++)
        for(int j=1; j<=m; j++)
        {
            c[i][j]=-1;
            nums[i][j]=INT_MAX;
        }
    for(int i=0; i<n; i++)
    {
        cin>>x>>y>>tc;
        c[x][y]=tc;
    }
    vist[0]=true;
    tp.x=1;
    tp.y=1;
    tp.lsc=0;
    tp.isc=0;
    tp.num=0;
    qu.push(tp);

    bfs();//

    if(imin!=INT_MAX)
        cout<<imin<<endl;
    else
        cout<<-1<<endl;

    return 0;
}

另外,网上别的dfs代码,很明朗,链接为https://www.luogu.org/problemnew/solution/P3956

#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
#define inf 0x7fffffff
int fx[4] = {-1, 0, 1, 0}; // x偏移量
int fy[4] = {0, -1, 0, 1}; // y偏移量
int f[110][110]; // 存储每个点的最优解
int mp[110][110]; // 存储初始棋盘
int m, n, ans = inf;
void dfs(int x, int y, int sum, bool frog)
{
    if(x < 1 || y < 1 || x > m || y > m) return; // 超出边界
    if(mp[x][y] == 0) return; // 无色区域
    if(sum >= f[x][y]) return; // 不符合最优解
        // 以上三种情况剪枝
    f[x][y] = sum;
    if(x==m && y==m) // 终点,坐标为(m, m)
    {
        if(sum < ans) ans = sum; // 更新最优解
        return;
    }
    for(int i = 0; i < 4; ++i)
    {
        int xx = x + fx[i];
        int yy = y + fy[i];
        if(mp[xx][yy]) // 若下一格有色
        {
            if(mp[xx][yy] == mp[x][y]) // 若颜色相同
                 dfs(xx, yy, sum, false); // 则不花钱
            else dfs(xx, yy, sum+1, false); // 否则花费+1
        }   else // 否则(若下一格无色)
        if(!frog) // (且)没有用过魔法
        {
            mp[xx][yy] = mp[x][y];
            dfs(xx, yy, sum+2, true); // 使用魔法
            mp[xx][yy] = 0;
        }
    }
}
int main()
{
    memset(f, 0x7f, sizeof(f));
    scanf("%d %d", &m, &n);
    for(int i = 1; i <= n; ++i)
    {
        int x, y, c;
        scanf("%d %d %d", &x, &y, &c);
        mp[x][y] = c + 1;
        // 1红色 2黄色 0无色(未赋值,其初值为0)
    }
    dfs(1, 1, 0, false);
    printf("%d", ans==inf ? -1 : ans);
    return 0;

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值