HDU 1198:Farm Irrigation

来源:互联网 发布:虚拟机软件有哪些 知乎 编辑:程序博客网 时间:2024/05/27 06:52


Farm Irrigation

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 9714    Accepted Submission(s): 4253


Problem Description
Benny has a spacious farm land to irrigate. The farm land is a rectangle, and is divided into a lot of samll squares. Water pipes are placed in these squares. Different square has a different type of pipe. There are 11 types of pipes, which is marked from A to K, as Figure 1 shows.


Figure 1


Benny has a map of his farm, which is an array of marks denoting the distribution of water pipes over the whole farm. For example, if he has a map 

ADC
FJK
IHE

then the water pipes are distributed like 


Figure 2


Several wellsprings are found in the center of some squares, so water can flow along the pipes from one square to another. If water flow crosses one square, the whole farm land in this square is irrigated and will have a good harvest in autumn. 

Now Benny wants to know at least how many wellsprings should be found to have the whole farm land irrigated. Can you help him? 

Note: In the above example, at least 3 wellsprings are needed, as those red points in Figure 2 show.
 

Input
There are several test cases! In each test case, the first line contains 2 integers M and N, then M lines follow. In each of these lines, there are N characters, in the range of 'A' to 'K', denoting the type of water pipe over the corresponding square. A negative M or N denotes the end of input, else you can assume 1 <= M, N <= 50.
 

Output
For each test case, output in one line the least number of wellsprings needed.
 

Sample Input
2 2DKHF3 3ADCFJKIHE-1 -1
 

Sample Output
23


总共有11种田地。建立结构体,来记录田地下方下水管道的情况。up,down,left,right。如果该田地有朝上的管道up=1,否则up=0.如果该田地有朝下的管道,down=1.

否则down = 0.如果该田地有朝左的管道,left=1,否则left=0,如果该田地有朝右的管道,right=1,right=0.

首先要把这11种田地下管道的情况存起来。

那么这里给出两种思路:

1.搜索解法,和搜索入门题统计油田个数的方法一样。挨个遍历M*N块田地,如果某块田地没有标记过,则以该块田地开始进行深搜或广搜,能够搜到的田地都进行标记。

代表这些田地与(源田地)相通。水井个数加1.

2.如果两块田地有管道相同,那么他们从属于一个集合。因此可以用并查集来处理。如果第s块田地与第t块田地有管道相通,求s和t所属的集合,如果他们已经在同一集合中。

不进行操作,否则进行集合合并操作。


1.搜索解法:

#include <iostream>#include <stdio.h>#include <string.h>#include <string>#include <math.h>#include <queue>#include <stdlib.h>#define INF 0x3f3f3f3fusing namespace std;const int MAXN = 55;int Map[MAXN][MAXN];int M,N;int vis[MAXN][MAXN];int dir[4][2] = {{-1,0},{0,1},{1,0},{0,-1}}; ///搜索顺序上右下左struct node{    int up;     ///上    int down;   ///下    int left;   ///左    int right;  ///右}area[13];struct pos{    int x;    int y;};void Init()     ///将11种土地下的管道情形都先列出来。{    memset(area,0,sizeof(area));    area[0].up = 1;   area[0].left = 1;    area[1].up = 1;   area[1].right = 1;    area[2].left = 1; area[2].down = 1;    area[3].down = 1; area[3].right = 1;    area[4].up = 1;   area[4].down = 1;    area[5].left = 1; area[5].right = 1;    area[6].up = 1;   area[6].left = 1;  area[6].right = 1;    area[7].up = 1;   area[7].left = 1;  area[7].down = 1;    area[8].left = 1; area[8].right = 1; area[8].down = 1;    area[9].up = 1;   area[9].down = 1;  area[9].right = 1;    area[10].up = 1;  area[10].down = 1; area[10].left = 1; area[10].right = 1;}void bfs(int x,int y)  ///广搜,也可以用深搜{    vis[x][y] = 1;    pos now,nex;    now.x = x;    now.y = y;    queue<pos>qu;    qu.push(now);    while(!qu.empty())    {        now = qu.front();        qu.pop();        for(int i = 0; i < 4; i++)        {            int temp = Map[now.x][now.y];  ///这个位置上的田地是哪一种田地            nex.x = now.x + dir[i][0];            nex.y = now.y + dir[i][1];            ///下一个点没有越界,而且没有访问过            if(nex.x>=0&&nex.x<M&&nex.y>=0&&nex.y<N&&vis[nex.x][nex.y]==0)            {                if(i == 0 && area[temp].up)    ///当前节点有朝上方的管道,并且搜索方向向上                {                    if(area[Map[nex.x][nex.y]].down)  ///看下一节点有没有朝下的管道                    {                        vis[nex.x][nex.y] = 1;                        qu.push(nex);                    }                }                if(i == 1 && area[temp].right) ///搜索方向向右,且有朝右的管道                {                    if(area[Map[nex.x][nex.y]].left)                    {                        vis[nex.x][nex.y] = 1;                        qu.push(nex);                    }                }                if(i == 2 && area[temp].down) ///当前搜索方向朝下,且有朝下的管道                {                    if(area[Map[nex.x][nex.y]].up)                    {                        vis[nex.x][nex.y] = 1;                        qu.push(nex);                    }                }                if(i == 3 && area[temp].left) ///当前搜索方向朝左,且有朝左的管道                {                    if(area[Map[nex.x][nex.y]].right)                    {                        vis[nex.x][nex.y] = 1;                        qu.push(nex);                    }                }            }        }    }}int main(){    char ch;    Init();    ///先给出每种土地下面管道的形态    while(~scanf("%d%d",&M,&N))    {        if(M == -1 && N == -1) break;        memset(vis,0,sizeof(vis));        for(int i = 0; i < M; i++)            for(int j = 0; j < N; j++)            {                scanf(" %c",&ch);                Map[i][j] = ch - 'A';            }        int ans = 0;        for(int i = 0; i < M; i++)            for(int j = 0; j < N; j++)            {                if(vis[i][j] == 0)                {                    ans++;                    bfs(i,j);                }            }        printf("%d\n",ans);    }    return 0;}


2.并查集解法。

#include <iostream>#include <stdio.h>#include <string.h>#include <string>#include <math.h>#include <queue>#include <stdlib.h>#define INF 0x3f3f3f3fusing namespace std;const int MAXN = 55;int Map[MAXN][MAXN];int M,N;struct node{    int up;     ///上    int down;   ///下    int left;   ///左    int right;  ///右}area[13];void Init(){    memset(area,0,sizeof(area));    area[0].up = 1;   area[0].left = 1;    area[1].up = 1;   area[1].right = 1;    area[2].left = 1; area[2].down = 1;    area[3].down = 1; area[3].right = 1;    area[4].up = 1;   area[4].down = 1;    area[5].left = 1; area[5].right = 1;    area[6].up = 1;   area[6].left = 1;  area[6].right = 1;    area[7].up = 1;   area[7].left = 1;  area[7].down = 1;    area[8].left = 1; area[8].right = 1; area[8].down = 1;    area[9].up = 1;   area[9].down = 1;  area[9].right = 1;    area[10].up = 1;  area[10].down = 1; area[10].left = 1; area[10].right = 1;}typedef struct Set{    int rrank;    int parent;}UFSTree;UFSTree t[MAXN*MAXN];   ///t[i]代表第i块田地。这里空间要开成MAXN*MAXNvoid MAKE_SET(UFSTree t[],int n){    for(int i = 0; i < n; i++)    {        t[i].rrank = 0;        t[i].parent = i;    }}int FIND_SET(UFSTree t[],int x){    if(x != t[x].parent)        return FIND_SET(t,t[x].parent);    else        return x;}void UNION(UFSTree t[],int x,int y){    if(t[x].rrank > t[y].rrank)        t[y].parent = x;    else    {        t[x].parent = y;        if(t[x].rrank == t[y].rrank)            t[y].rrank++;    }}int main(){    char ch;    Init();    ///先给出每种土地下面管道的形态    while(~scanf("%d%d",&M,&N))    {        if(M == -1 && N == -1) break;        for(int i = 0; i < M; i++)            for(int j = 0; j < N; j++)            {                scanf(" %c",&ch);                Map[i][j] = ch - 'A';            }        MAKE_SET(t,M*N);  ///有M*N块田                int temp1,temp2;        for(int i = 0; i < M; i++)            for(int j = 0; j < N; j++)            {                if(j+1<N)  ///该点与该点下侧的田地                {                    temp1 = i*N+j;                    temp2 = i*N+j+1;                    if(area[Map[i][j]].right && area[Map[i][j+1]].left)                    {                        temp1 = FIND_SET(t,temp1);                        temp2 = FIND_SET(t,temp2);                        if(temp1 != temp2)                            UNION(t,temp1,temp2);                    }                }                if(i+1<M)  ///该点与该点右侧的田地                {                    temp1 = i*N+j;      ///第temp1块田                    temp2 = (i+1)*N+j;  ///第temp2块田                    if(area[Map[i][j]].down && area[Map[i+1][j]].up)                    {                        temp1 = FIND_SET(t,temp1);                        temp2 = FIND_SET(t,temp2);                        if(temp1 != temp2)  ///两块田不在一个分离集合树                            UNION(t,temp1,temp2);                    }                }            }        int ans = 0;        for(int i = 0; i < M*N; i++)        {            if(t[i].parent == i)                ans++;        }        printf("%d\n",ans);    }    return 0;}


0 0
原创粉丝点击