1144 农场灌溉

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

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

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

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

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

输出样例
2 3

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

#include 

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;ifor(j=0;jif(state[i*m+j]==big)
            state[i*m+j]=small;    //把之前延伸到big所在农田块的农田,一次性全部延伸到small所在
                                   //向左上延伸
     }


} inbound(int row,int col)
{
    if(row>=0&&col>=0&&rowreturn 1;
    return 0;
}
void search()
{  int i,j,k;
   int i1,j1,row1,row2;    //状态数组的下标
   for(i=0;ifor(j=0;jfor(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//先把每一块农田看做独立的
            for(j=0;jcin>>a[i][j];
            }

            search();
        sum=0;
        for(i=0;iif(state[i]==i)
            sum++;
        cout<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(bigfor(i=0;i<m;i++)
        for(j=0;jif(state[i*m+j]==big)
            state[i*m+j]=small;    //把之前延伸到big所在农田块的农田,一次性全部延伸到small所在
                                   //向左上延伸
     }


}

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

你可能感兴趣的:(算法,noj,c++)