• uva 657 The die is cast


    图的搜索,双重搜索

    题意:(折腾的UVA又是好难懂的题意),给你一个h行w列的矩阵输入(标准的),注意输出w h,别颠倒过来。然后只有三种点 '*' , '.' , 'X'

    其中X和*一起称为区域I,在区域I中相连的X称为区域II , 输出就是输出m个数字,其中m就是区域I的个数,这m个数字中第i个数字num[i]表示某块区域I一面又多少个区域II

    其中相连是两个格子有公共边,只有点不行,所以对于一个格子而言有4个相连的格子,分别就是上下左右

    另外区域I可能是任意形状的,可以看sample

    sample中就是有4块区域I

    左上角的区域I有两个X,但是这个两个X不是相连的,算为2个,所以这个区域I对应的数字是2

    右上角的区域II有两个X,不过这两个X是相连的,算为1个,所以这个区域I对应的数字是1

    左下角的区域I有两个X,不过这两个X不想连,算为2个,所以这个区域I对应的数字是2

    右下角的区域有四个X,不过这4个X都不相连,算为4,所以这个区域对应的数字是4

    所以最优的数字是2 1 2 4  ,输出要求排序后输出,所以是1 2 2 4

     

    题意说完了就说算法

    双重搜索,DFS和BFS都行,我用了DFS+BFS,其实怎么搭配都可以的,应该都不会TLE或者什么

    图中只有X和*的点会被访问

    对于当前点如果没被访问过而且是X或者*,就准备访问它

    优先判断它是不是X,如果是,则先执行BFS,把和这个X相连的X全部找出来,找这些X的时候并不是标记他们被访问过,而是不用标记被访问过,而在在图中将它们改为*

    然后BFS结束后,那一部分X已经变为*,然后再从起点开始DFS所有的*,并且标记被访问,注意这时候才标记被访问

    所以可以看到*只会被访问一次,是被DFS访问的

    X会被访问两次,首先被BFS访问并改为*,再被DFS访问一次

     

    统计有图中多少个区域I是看主函数中调用了多少次DFS,主函数每调用一次DFS就计数一次,其实就是判断图中有多少个连通分量

    而每调用一个BFS,就给区域II计数一次,BFS只会在DFS中被调用

    所以再啰嗦一句就是DFS是访问区域I的,BFS是在区域I中访问区域II的

    另外注意,一个区域I中的区域II的个数只能是1到6,0和6以上的不能算进去,相当于忽略掉这整块区域I

    然后看代码

    //只有vis[i][j]为0,而且s[i][j]='*'或者s[i][j]='X'的点会被访问
    //对于确定要访问的点,优先判断s[i][j]是不是'X',是的话进行BFS访问到所有的'X'
    //访问过程中,不用标记vis[i][j],也是将'X',改为'*'
    //BFS结束后相当于很多'X'都变成了没有标记过的'*',然后就简单的DFS所有的'*'
    //每进行一次BFS就计数
    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    #include <queue>
    using namespace std;
    #define N 60
    struct node 
    { int x,y; };
    queue <struct node> q; 
    char s[N][N];
    int vis[N][N];
    int w,h;
    int dx[5]={0,-1,1,0,0} , dy[5]={0,0,0,-1,1};
    int ccount;
    
    void BFS(int i , int j)
    {
        int xx,yy;
        struct node tmp,ttmp;
    
        while(!q.empty()) q.pop();  //清空队列
        s[i][j]='*';
        tmp.x=i;  tmp.y=j;
        q.push(tmp);  //初始化队列先放一个点进去
        while(!q.empty())
        {
            tmp=q.front();
            q.pop();
            for(int k=1; k<=4; k++)
            {
                xx=tmp.x+dx[k];
                yy=tmp.y+dy[k];
                if(!vis[xx][yy] && s[xx][yy]=='X')
                {
                    s[xx][yy]='*';
                    ttmp.x=xx;
                    ttmp.y=yy;
                    q.push(ttmp);
                }
            }
        }
        return ;
    }
    
    void DFS(int i, int j)
    {
        int xx,yy;
        if(s[i][j]=='X')  //优先判断是不是'X',然后进行BFS
        {
            ccount++;
            BFS(i,j);
        }
    
        vis[i][j]=1;
        for(int k=1; k<=4; k++)
        {
            xx=i+dx[k];
            yy=j+dy[k];
            if(!vis[xx][yy] && (s[xx][yy]=='*' || s[xx][yy]=='X') )
                DFS(xx,yy);
        }
    
        return ;
    }
    
    void input()
    {
        memset(s,0,sizeof(s));
        memset(vis,0,sizeof(vis));
    
        for(int i=1; i<=h; i++)
            gets(s[i]+1);
        
        for(int i=0; i<=h+1; i++) //标记左右两侧
            vis[i][0]=vis[i][w+1]=1;
        for(int i=0; i<=w+1; i++) //标记上下两行
            vis[0][i]=vis[h+1][i]=1;
    /*
        for(int i=0; i<=h+1; i++)
        {
            for(int j=0; j<=w+1; j++)
                printf("%d",vis[i][j]);
            printf("\n");
        }
        for(int i=1; i<=h; i++)
            printf("%s\n",s[i]+1);
    */
        return ;
    }
    int main()
    {
        int T=0,c,num[N*N];
        while(scanf("%d%d",&w,&h)!=EOF)
        {
            getchar(); T++;
            if(!w && !h)  break;
            input();
    
            c=0;
            for(int i=1; i<=h; i++)
                for(int j=1; j<=w; j++)
                    if( (vis[i][j] && s[i][j]=='X' || s[i][j]=='*') )
                    {
                        ccount=0;
                        DFS(i,j);  
                        if(ccount>0 && ccount<7)
                            num[c++]=ccount;
                    }
            sort(num,num+c);
            printf("Throw %d\n",T);
            printf("%d",num[0]);
            for(int i=1; i<c; i++)
                printf(" %d",num[i]);
            printf("\n\n");
    
        }
        return 0;
    }
  • 相关阅读:
    BOM与DOM的区别与联系
    HTTP与HTTPS的区别
    总结一下C++与C#之间的区别
    点标记(lambda表达式+linq查询标记符)与linq语句(查询表达式)
    java多线程:继承Thread和实现Runable接口的区别
    打印BroadcastReceiver的所有接受者
    修改apk里面的源码
    关于启动模式中的问题
    onSaveInstanceState和onRestoreInstanceState()
    Options Menu的android3.0以上和以下版本显示刷新原理,刷新适配
  • 原文地址:https://www.cnblogs.com/scau20110726/p/2764626.html
Copyright © 2020-2023  润新知