ZOJ---2412:Farm Irrigation【油田问题】

本文介绍了一个基于连通区域计数的农田灌溉模拟算法。通过将不同类型的灌溉管道转化为数字矩阵,并利用深度优先搜索(DFS)算法来计算最少需要设置的水源数量,确保整个农田得到充分灌溉。

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. 

 

题意:

A-K分别代表农田里不同的灌溉管道的铺设形状,输入一个字母矩阵,求这个矩阵农田最少需要多少个水源。

题解:

这个题就是油田问题的变形,还是求连通区域的个数。可以先将A-K的形状在二维数组0,1标记,在输入时转化成数字矩阵,然后就是油田问题的DFS搜索了。

AC代码:

 #include<iostream>
using namespace std;
int mapp[200][200];
int n,m;
int xx[4]={-1,1,0,0};       // 四个移动的方向
int yy[4]={0,0,-1,1};
bool check(int x,int y)     //检查(x,y)点是否已经搜过了
{
    if(x>=0&&x<m*3&&y>=0&&y<n*3&&mapp[x][y])
        return true;        //前面3个且 是判断是否越界,后面判断是否走过
    else return false;
}
void dfs(int x,int y)
{
    mapp[x][y]=0;           //走到(x,y)点就把它标记了
    for(int i=0;i<4;i++)
    {
        int fx=x+xx[i];     //四个方向移动
        int fy=y+yy[i];
        if(check(fx,fy))
            dfs(fx,fy);     //如果(fx,fy)没有走过,就从这个点又开始搜
    }
}
int vis[11][9] {{0,1,0,1,1,0,0,0,0},{0,1,0,0,1,1,0,0,0},{0,0,0,1,1,0,0,1,0},{0,0,0,0,1,1,0,1,0},{0,1,0,0,1,0,0,1,0},{0,0,0,1,1,1,0,0,0},{0,1,0,1,1,1,0,0,0},{0,1,0,1,1,0,0,1,0},{0,0,0,1,1,1,0,1,0},{0,1,0,0,1,1,0,1,0},{0,1,0,1,1,1,0,1,0}};
    int main()              //上面那行就是标记A-K,下标0-10代表A-K,下标0-8是一个字母的3*3矩阵的0,1标记。
    {
        string ss;
        while(cin>>m>>n)    
        {
            if(n==-1&&m==-1) return 0;
            for(int i=0; i<m; i++)
            {
                cin>>ss;    //输入一行字母
                for(int p=0; p<3; p++) //3*3矩阵的行
                {
                    for(int j=0; j<ss.size(); j++)
                    {                         //遍历一行输入的字母
                        int t=ss[j]-'A';
                        for(int q=0; q<3; q++)//3*3矩阵的列
                            mapp[i*3+p][j*3+q]=vis[t][3*p+q];//下标关系的转换
                    }
                }
            }
            int ans=0;
            for(int i=0;i<m*3;i++)
            {
                for(int j=0;j<n*3;j++)
                {
                    if(mapp[i][j])    //遍历转换后的数字矩阵,(i,j)为1就DFS,将该点周围的联通点标记为0.
                    {
                        ans++; 
                        dfs(i,j);
                    }
                }
            }
            cout<<ans<<endl;
        }
        return 0;
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值