1144 农场灌溉

时限:1000ms 内存限制:10000K 总时限:3000ms

描述
一农场由图所示的十一种小方块组成,蓝色线条为灌溉渠。若相邻两块的灌溉渠相连则只需一口水井灌溉。
这里写图片描述

输入
给出若干由字母表示的最大不超过50×50具体由(m,n)表示,的农场图

输出
编程求出最小需要打的井数。每个测例的输出占一行。当M=N=-1时结束程序。

输入样例
2 2 DK HF 3 3 ADC FJK IHE -1 -1

输出样例
2 3

提示
参考迷宫问题,实现时关键要解决好各块的表示问题。
分析:该问题与迷宫问题相似,都采用广度优先搜索,不同的是,农场灌溉问题只往上和往左搜索,因为涉及到水渠的连接问题,如果右边和左边的正好相连,或下面和上面的正好相连,则将其合并

#include <iostream>

using namespace std;
char a[50][50];    //农场构造
int state[2500];//每一块农田往最上最左可以追溯到哪一块
int m,n;
int move[2][2]={{0,-1},{-1,0}};//分别表示农田的上方和左方两
void merge(int row1,int row2)
{    int temp,big,small;
     int i,j;
     big=state[row1];
     small=state[row2];
     for(i=0;i<m;i++)
        for(j=0;j<n;j++)
     {
         if(state[i*m+j]==big)
            state[i*m+j]=small;    //把之前延伸到big所在农田块的农田,一次性全部延伸到small所在
                                   //向左上延伸
     }


} inbound(int row,int col)
{
    if(row>=0&&col>=0&&row<m&&col<n)
        return 1;
    return 0;
}
void search()
{  int i,j,k;
   int i1,j1,row1,row2;    //状态数组的下标
   for(i=0;i<m;i++)
    for(j=0;j<n;j++)
    {
        for(k=0;k<2;k++)
        {
            i1=i+move[k][0];
            j1=j+move[k][1];  //分别表示农田的上方和左方两个位置
            if(!inbound(i1,j1))
                continue;        //越界,结束本次循环,开始下一次
             row1=i*m+j;        //把二维数组转化成一维数组
             row2=i1*m+j1;
            if(k==0)         //当前块与其左边一块农田的关系
            {
                if(a[i][j]=='A'||a[i][j]=='C'||a[i][j]=='F'||a[i][j]=='G'||a[i][j]=='H'||a[i][j]=='I'||a[i][j]=='K')
                    //有一条连向左边那条边的横线
                    if(a[i1][j1]=='B'||a[i1][j1]=='D'||a[i1][j1]=='F'||a[i1][j1]=='G'||a[i1][j1]=='I'||a[i1][j1]=='J'||a[i1][j1]=='K')
                    //在a[i][j]左边刚好有一条横着连向右边的边的横线
                    merge(row1,row2);    //合并这两块
            }
            else
            {
                if(a[i][j]=='A'||a[i][j]=='B'||a[i][j]=='E'||a[i][j]=='G'||a[i][j]=='H'||a[i][j]=='J'||a[i][j]=='K')
                //向上延伸
                    if(a[i1][j1]=='C'||a[i1][j1]=='D'||a[i1][j1]=='E'||a[i1][j1]=='H'||a[i1][j1]=='I'||a[i1][j1]=='J'||a[i1][j1]=='K')
                    //向下延伸
                    merge(row1,row2);     //合并这两块
            }
        }

    }

}
int main()
{   int i,j,sum;
    while(true)
    {
       cin>>m>>n;
       if(m<0||n<0)
        break;
        for(i=0;i<m;i++)         //先把每一块农田看做独立的
            for(j=0;j<n;j++)
            {
             state[i*m+j]=i*m+j;
             cin>>a[i][j];
            }

            search();
        sum=0;
        for(i=0;i<n*m;i++)
            if(state[i]==i)
            sum++;
        cout<<sum<<endl;

    }
    return 0;
}

关于合并的函数,本来参照之前的答案,我是这样写的

void merge(int row1,int row2)
{    int temp,big,small;
     int i,j;
     big=state[row1];
     small=state[row2];
     if(big==small)
        return;
     if(big<small)
     {
         temp=big;
         big=small;
         small=temp;
     }
     for(i=0;i<m;i++)
        for(j=0;j<n;j++)
     {
         if(state[i*m+j]==big)
            state[i*m+j]=small;    //把之前延伸到big所在农田块的农田,一次性全部延伸到small所在
                                   //向左上延伸
     }


}

但是考虑到本问题解决问题的顺序本来就是从左到右上到下,所以big所代表的状态值按照常规是比其左边或上边的大的,所以作者省略了比较的部分。
出现的问题:一开始运行的时候,不管怎么样,输出的结果即sum值都不对。最后经检查是,j1=j+move[k][1];这一句写成了j1=j+move[k][0];细心!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值