时限: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];
细心!