2015年安徽省程序设计大赛题,梯田问题题解

来源:互联网 发布:悟空传 知乎 编辑:程序博客网 时间:2024/05/01 10:18

梯田

Time Limit: 2000 MSMemory Limit: 65536 KBTotal Submissions: 136Accepted: 38

Description


土豪YZK在一块小岛上有着一大片n*m的梯田,每块1*1的田地都有它的高度。奴隶们不甘被YZK剥削,他们联合起来决定发动一场海啸淹掉YZK的梯田,因为要留一部分给自己吃,所以他们决定至少淹掉p块田地,但是不能超过q块田地,否则会因为剩下的田地不够而把奴隶自己饿死。现在给你一个n*m的矩阵,代表梯田中每块田地的高度,求能否发动一场高度为h的海啸,使得满足奴隶们的要求。由于发动海啸代价很高,所以如果存在多个解,请输出最小的一个h,否则输出-1



Input


第一行是一个正整数T,代表数据组数

对于每组数据,第一行为四个整数nmpq

之后是一个n*m的矩阵,矩阵中每个整数代表每块田地高度

1<=T<=100

1<=n,m<=100

1<=p<=q<=n*m

1<=梯田高度<=1000000


Output


对于每组数据,如果能找到h,请输出最小的h,否则输出-1

每组输出占一行


Sample Input


2
3 3 3 6
1 2 3
4 5 6
7 8 9
4 4 5 6
1 2 2 1
2 1 1 2
2 1 1 2
1 2 2 1

Sample Output


3
-1

Hint


一块田地被淹的条件为:
一、它自身的高度<=h
二、它相邻的四块田地中至少有一块被淹没

我们可以认为,海啸发动的时候,梯田的外面都处于被淹没状态。



这是我遇到的一条比较烦的dfs求联通快问题+二分法。。

一开始dfs除了问题,搞了半天发现,条件写的有问题,不应该递归遍历周围8块,而应该是上下左右4块



后来二分法也出了一点问题,好在现在都解决了。。


代码如下


#include<cstdio>
#include<iostream>
#include<cstring>
#include<map>
#include<vector>
#include<iostream>
#include<set>
#include<cmath>
using namespace std;


int a[105][105];
int graph[105][105];




int countn=0;






void dfs(int x,int y,int m,int n,int h)
{
 
    if(x<0||x>m||y<0||y>n) return;
    if(graph[x][y]==-1||graph[x][y]>h) return;//如果已经被标记或者高于海浪,就返回 
    graph[x][y]=-1;//标记 
    countn++;//为被淹的数量,包括了边界 
    dfs(x-1,y,m,n,h);
    dfs(x,y+1,m,n,h);
    dfs(x,y-1,m,n,h);
    dfs(x+1,y,m,n,h);
}








void qian()
{
    for(int i=0;i<=104;i++)
        for(int j=0;j<=104;j++)
            graph[i][j]=a[i][j];
    countn=0;//初始时将图还原成出状态也可以用memset 
}








int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int H;
        int flag=0;//标记这样的H是否真的存在
 
        memset(a,0,sizeof(a));
        memset(graph,0,sizeof(graph));
  
        int n,m,p,q;
        cin>>n>>m>>p>>q;//n*m的矩阵  //至少淹掉p,之多q
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                cin>>a[i][j];
        int left=0;
        int right=1000000;

        int mid;
        while(right-left>1)//二分法找值 
        {
           qian();
          mid=(left+right)/2;
           dfs(0,0,n+1,m+1,mid);
            int mmm=countn-2*m-2*n-4;//mmm为被淹的田块数目 
            if(mmm>q)
                right=mid;
            else 
if(mmm<p)
                left=mid;
            else
            {
                right=mid;
                flag=1;//如果存在出于(p,q)之间的结果,就说明,这样的高度H 是存在的,否则不存在 
                 H=mid;//此时left为小于p的最后一个高度,那mid或者right就是大于等于p小于等于q的第一个值 
            }
         


        }
        if(!flag)//如果flag=0,则不存在 
            cout<<-1<<endl;
        else//否则输出是被淹田块数目大于等于p小于等于q的第一个值 
            cout<<H<<endl;
        
        
    }
   return 0;
}

0 0
原创粉丝点击