• 2018.8.16 题解 2018暑假集训之球迷



    球迷

    【问题描述】

    一个球场C的球迷看台可容纳M*N个球迷。官方想统计一共有多少球迷群体,最大的球迷群体有多少人。

    球迷选座特性:同球迷群体会选择相邻座位,不同球迷群体选择不相邻的座位。(相邻包括前后相邻、左右相邻、斜对角相邻);

    给定一个M*N的二位球场,0代表该位置没人,1代表该位置有人,希望输出球队群体个数P,最大的球队群体人数Q。

    【输入】

    第一行,2个数字,M、N,使用英文逗号隔开。

    接下来M行,每行N个数字,使用英文逗号隔开。

    【输出】

    一行,2数字,P和Q。

    【输入输出样例】

    fans.in

    fans.out

    10,10

    0,0,0,0,0,0,0,0,0,0

    0,0,0,1,1,0,1,0,0,0

    0,1,0,0,0,0,0,1,0,1

    1,0,0,0,0,0,0,0,1,1

    0,0,0,1,1,1,0,0,0,1

    0,0,0,0,0,0,1,0,1,1

    0,1,1,0,0,0,0,0,0,0

    0,0,0,1,0,1,0,0,0,0

    0,0,1,0,0,1,0,0,0,0

    0,1,0,0,0,0,0,0,0,0

    6,8

    【数据范围】

    对于100%的数据,1<=M,N<=3×103


     

    突然想抱怨两句

    本题为今日头条笔试题 原来的数据范围是100*100 然鹅老师为了尊重我们的智商放到了3000*3000加上字符串

    由于有一个可恶的TLE 所以本题明显不能用裸的bfs(queue实在太慢了)

    本人水平有限不会优化bfs 所以在这里采用dfs

    于是本题便转化成了一个不用回溯的dfs问题

    那么问题来了:咋dfs?为什么不需要回溯???(来自已经快忘了dfs的蒟蒻)


    我们首先复习一下啥是dfs

    来自百度百科

    其实就是从一个方向搜完一整条路线再搜下一条路线

    对于一般的dfs(可以参照全排列等经典例题)由于每一种情况都要考虑到所以需要回溯

    但是对于本题来讲并不存在“走和不走”的逻辑矛盾所以并不需要回溯

    咋搜看代码吧


    #include<iostream>
    using namespace std;
    int m,n,cnt,tmp,maxn;//cnt存储有几组 tmp存储每组几个 maxn存储最多人数 
    char ch,map[3050][3050];//为了防止MLE以及TLE把地图存成字符 ch用来读',' 
    static const int dx[8]={-1,1,0,0,-1,-1,1,1},dy[8]={0,0,-1,1,-1,1,1,-1};//方向数组 
    inline int read()
    {
        int x,f=1;
        char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
        for(x=ch-'0';isdigit(ch=getchar());x=x*10+ch-'0');
        return x*f;
    }//读入优化 本质上还是getchar() 注意cin会TLE 
    void dfs(int x,int y)//dfs x、y是横纵坐标 
    {
        for(int i=0;i<8;i++)//八个方向 
        {
            int tx=x+dx[i],ty=y+dy[i];//目标点 
            if(map[tx][ty]=='1'&&tx>0&&tx<=m&&ty>0&&ty<=n)//可以到达而且不会越界 
            {
                tmp++;//本组人数加一 
                map[tx][ty]='0';//避免重复经过(很重要的剪枝) 
                dfs(tx,ty);//递归搜索下一个目标点 
             } 
        }
        return;//八个方向都搜不到就返回下一条路 
    }
    int main()
    {
        m=read(),ch=getchar(),n=read();//ch处理逗号 
        for(int i=1;i<=m;i++)
        {
            for(int j=1;j<=n;j++)
            {
                ch=getchar();
                map[i][j]=getchar(); 
            }
        }//划重点!!!
        //前面我们已经提到过了m,n后面会有一个回车
        //而getchar是会读回车的
        //所以对于每一个点我们在读入时可以划分成两个部分:一个字符(回车或逗号)+键值 
        for(int i=1;i<=m;i++)
        {
            for(int j=1;j<=n;j++)
            {
                if(map[i][j]=='1')//找到一个可以开始搜索的点 
                {
                    cnt++;//增加一组 
                    dfs(i,j);//从当前位置搜索 
                    if(tmp>maxn)maxn=tmp;//更新人数最大值 
                    tmp=0; //注意归零 
                } 
            }
        }
        printf("%d,%d",cnt,maxn);
        return 0;
    }

    本题是一道经典的dfs例题 可供大家参考学习

    /*====年轻人,瞎搞是出不了省一的,这就是现实====*/
  • 相关阅读:
    服务器键盘设置错误 完美解决
    windows 彻底删除360文件 360zipext.dll 等等
    VS2005智能设备中无法找到PInvoke DLL
    如何使用DotNet 2.0中的应用程序配置 Settings.settings
    维护应用程序状态(一):使用浏览器cookie
    NHibernate学习导航
    HTML基础(三):基本的HTML标签
    使用Cookie对象保存用户自定义设置
    ASP.NET2.0 个性化用户配置
    sealed修饰符的使用
  • 原文地址:https://www.cnblogs.com/qxds/p/9490417.html
Copyright © 2020-2023  润新知