水田问题

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.
InputThere 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.
OutputFor each test case, output in one line the least number of wellsprings needed.
Sample Input
2 2
DK
HF

3 3
ADC
FJK
IHE

-1 -1
Sample Output
2
3

题目:题意就是有A到K11种田,任意输入两个数字,范围为1到50,求组成的水田最多需要多少个水泵?

传统思路:这题传统思路就是,先将组成的图表示出来,判断每个小图片四周的节点,如果可以连,就从下一个图片一直暴力下去,直到走不下去为止。然后将走过的所有路标记一下,在遍历组成的图,重复上诉步骤,直到所有位置都被标记。这种方法使能够解出来的,题目要求的范围比较小,开的时间为1s,完全可以暴力。这里,我们讲另一种思路。

二进制求解:用个数组将所有图片分别用一个数来表示,这里采用的是二进制的形式,下为起始位置,逆时针旋转,有端点为1,无端点为0。其思路是,以每个字符为起点,向上下左右进行查找,直到找到重复的点或越界为止。这里有一点必须注意,那就是首先我们需要把所有字符串都存起来,不能边存边查。这样做的目的很明显,就是为了减少运行数据,避免重复,达到优化的目的。我们查找的时候是运用了贪心的思想,把附近能达到的都走一遍,然后都标记,后面就不需要再查找了。而且,如果把后面的标记判断那一步(if(ans[i][j])  continue) 删了,就会出错,原因是一旦删了,后面已经被标记的还会重复计算,ans还是会多加重复的次数,所以那一步是必须的。//这是图像转化为数字

水田问题_第1张图片

水田问题_第2张图片

话不多说,代码如下:

#include 
#include 
#include 
#include 
#include 
using namespace std;
char s[55][55];
int vis[55][55],xx[]= {0,0,1,-1},yy[]= {1,-1,0,0},tp[]= {3,6,9,12,10,5,7,11,13,14,15}; //利用二进制,从最下面开始,有端点表示为1,无端点表示为0
int flag,n,m,ans;
int check(int x,int y,int tx,int ty,int cn)
{
    flag=0;
    if(tx<1||tx>n||ty<1||ty>m)//判断是否越界
        return false;
    int ta,tb;
    ta=s[x][y]-'A';
    tb=s[tx][ty]-'A';
    if(cn==0)//向右查找
    {
        if(((tp[ta]>>2)&1)&&(tp[tb]&1))
            flag=true;
    }
    else if(cn==1)//向左查找
    {
        if(((tp[tb]>>2)&1)&&(tp[ta]&1))
            flag=true;
    }
    else if(cn==2)//向上查找
    {
        if(((tp[ta]>>3)&1)&&((tp[tb]>>1)&1))
            flag=true;
    }
    else//向下查找
        if(((tp[tb]>>3)&1)&&((tp[ta]>>1)&1))
            flag=true;
    return flag;
}
void dfs(int x,int y)
{
    if(vis[x][y])//从当前位置向四处查找,直到找到某个位置是走过的位置为止
        return;
    vis[x][y]=1;//把所有走过的地方都标记一次
    for(int i=0; i<4; i++) //上下左右都进行查找
    {
        int tx=x+xx[i];
        int ty=y+yy[i];
        if(check(x,y,tx,ty,i))
            dfs(tx,ty);
    }printf("%d\n",ans);
}
int main()
{
    int i,j;
    while(~scanf("%d %d",&n,&m)&&(n+1)&&(m+1))
    {
        ans=0;
        memset(vis,0,sizeof(vis));
        for(i=1; i<=n; i++)
            scanf("%s",s[i]+1);//下标从1开始
        for(i=1; i<=n; i++)
        {
            for(j=1; j<=m; j++)
            {
                if(vis[i][j])//如果已经走过,就不必再走了,而不是相同的元素不能重复
                    continue;
                ans++;
                dfs(i,j);
            }
        }
        printf("%d\n",ans);
    }
    return 0;


}

大家还有任何疑问欢迎留言,大家一起进步!

你可能感兴趣的:(算法)