uva572--dfs求八连块

来源:互联网 发布:office for mac破解 编辑:程序博客网 时间:2024/04/27 20:00

题意:

输入一个 m 行 n 列的字符矩阵,统计字符 @ 能组成多少八连块,如果两个字符 @ 所在的格子相邻(横竖或者对角线的方向),就

说他们组成了一个八连块,问图中一共有多少个八连块。



Sample Input:

1 1

*

3 5

*@*@*

 **@**

*@*@*

1 8

@@****@*

5 5

****@

*@@*@

*@**@

@@@*@

@@**@

0 0

Sample Output:

0

1

2

2



分析:

图和二叉树一样,也有自己的dfs 和 bfs遍历,一般dfs用来求连通块问题,bfs用来找最短路问题,这个题目就是一个典型的dfs求八

连块的问题,可以从每个 @ 字符出发,递归遍历他周围八个方向的字符,看是否是 @ 格子,如果是就标记一下,证明该格子遍历

过,这样在以后的访问的时候,就能知道他是否被访问过,从而避免同一个格子被访问多次。下面的代码用一个二重循环来寻找八

连块,当然也可以用常量数组或者8条dfs遍历,在这里说一下,图的dfs遍历用递归实现,bfs遍历则是用队列(或者数组)实现,

类似的还有求二连块,四连块,等等,都可以用dfs遍历来实现,只需要改一下行走函数就可以。


下面上代码:

#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>using namespace std;int n, m, maxz[105][105];char str[105][105];void dfs(int r,int c,int id){    if(r < 0 || r >= n ||c < 0 ||c >= m)        return;    if(maxz[r][c] > 0 || str[r][c] != '@')        return;    maxz[r][c] = id;    for(int dr = -1; dr <= 1; dr++)///两个方向同时移动可以往八个方向移动        for(int dc = -1; dc <= 1; dc++)///而四连块则是单移动,仅一个for循环。            if(dr != 0 || dc != 0)///这儿同时体现八连块,八方向                dfs(r + dr, c + dc, id);}int main(){    while(scanf("%d%d",&n, &m) == 2&&n,m)    {        for(int i = 0; i < n; i++)            cin >>str[i];        memset(maxz, 0, sizeof(maxz));        int cnt = 0;        for(int i = 0; i < n; i++)            for(int j = 0; j < m; j++)            {                if(str[i][j] == '@'&&maxz[i][j] == 0)                {                    dfs(i,j, ++cnt);                    cnt = max(0, cnt);                }            }        cout <<cnt<<endl;    }}


下面上四连块:

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;const int maxn=100+5;int maze[maxn][maxn];///顶点访问状态int R,C,K;///R行C列K个水块int cnt,ans;///cnt是计算访问的格子数///两个表示方向数组int dr[]= {-1,1,0,0}; //上,下,左,右int dc[]= {0,0,-1,1};void dfs(int r,int c) ///r是行坐标,c是列坐标{    if(r<1||r>R ||c<1||c>C || maze[r][c]==0)        return ;///超出范围或已经访问过的格子    maze[r][c] = 0;///访问的格子    cnt++;    for(int d=0; d<4; d++)///四连块        dfs(r+dr[d],c+dc[d]);}int main(){    while(scanf("%d%d%d",&R,&C,&K) == 3)    {        for(int i=1; i<=R; i++)///一定是从1开始            for(int j=1; j<=C; j++)                maze[i][j] = 0;///将初始的maze数组全部设置成false        while(K--)///输入有水的格子坐标,设置成true        {            int i,j;            scanf("%d%d",&i,&j);            maze[i][j] = 1;        }        ans=0;        for(int i=1; i<=R; i++)            for(int j=1; j<=C; j++)                if(maze[i][j]==1)                {                    cnt=0;                    dfs(i,j);                    ans=max(ans,cnt);///如果没有则输出0                }        printf("%d\n",ans);    }    return 0;}



下面上二连块:

代码实现:#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>using namespace std;int map[650][650],p[650][650],x[650],y[650],vis[650];int n,num,t,k;char s[650][650];bool Search(int i)///其实就是一个dfs{    int j;    for(j=0; j<num; j++)    {        if(map[i][j] && !vis[j])        {            vis[j]=1;            if(!y[j]||Search(y[j]))            {                y[j]=i;                x[i]=j;                return true;            }        }    }    return false;}int  match(){    memset(x,0,sizeof(x));    memset(y,0,sizeof(y));    int ans=0;    for(int i=0; i<num; i++)///寻找増广路    {        memset(vis,0,sizeof(vis));        if(Search(i))///统计满足二连块的个数            ans++;    }    return ans/2;}int main(){    k=1;    cin>>t;    while(t--)    {        memset(map,0,sizeof(map));        cin>>n;        for(int i=0;i<n;i++)        {            for(int j=0;j<n;j++)                cin>>s[i][j];        }        for(int i=0;i<n;i++)        {            for(int j=0;j<n;j++)            {                if(s[i][j]=='#')                    p[i][j]=num++;            }        }        for(int i=0;i<n;i++)        {            for(int j=0;j<n;j++)            {                if(s[i][j]=='#')                {                    if(j<n-1 && s[i][j+1]=='#')                    {                        map[p[i][j]][p[i][j+1]]=1;                        map[p[i][j+1]][p[i][j]]=1;                    }                    if(j<n-1 && s[i+1][j]=='#')                    {                        map[p[i][j]][p[i+1][j]]=1;                        map[p[i+1][j]][p[i][j]]=1;                    }                }            }        }        int p=match();        printf("Case %d: %d\n",k++,p);    }    return 0;}



1 0