洛谷3933 Chtholly Nota Seniorious 二分答案+贪心

题目链接

题意

给你一个N*M的矩阵 (N,M <=2000)  把他分成两部分 使两部分的极差较大的一个最小  求这个最小值。然后分矩阵的要求是:每个部分内部的方块之间,可以通过上下左右相互到达,而且每个内部的方块之间互相到达,最多允许拐一次弯(不能出现“凹”233)

 

二分答案+贪心

二分上界是矩阵max-min   

判断的时候 由于 分开的矩阵在每一行肯定是连续的 所以就按顺序扫一遍 判断一下在哪里分开即可

还有就是由于最大值最小值所在的位置不确定 ,我们需要旋转3次这个矩阵然后求最优答案

代码 

#include<bits/stdc++.h>
#define MAXN 2017
#define INF 0x7f7f7f7f
using namespace std;
int N,M,a[MAXN][MAXN],maxa,mina=INF,ans=INF;
bool check(int tmp){
    int pos=1;
    for(int i=1;i<=N;i++)
    {
        for(int j=1;j<=M;j++)
            if(a[i][j]<maxa-tmp)
                pos=max(j+1,pos);
        for(int j=1;j<=M;j++)
            if(a[i][j]>mina+tmp)
                if(j<pos)return 0;
    }
    return 1;
}
int Solve(){
    int l=0,r=maxa-mina;
    while(l<r){
        int mid=l+r>>1;
        if(check(mid))r=mid;
        else l=mid+1; 
    } 
    return l;
}
void flip1(){
    for(int i=1;i<=N/2;i++)
        for(int j=1;j<=M;j++)
            swap(a[i][j],a[N-i+1][j]);
} 
void flip2(){
    for(int j=1;j<=M/2;j++)
        for(int i=1;i<=N;i++)
            swap(a[i][j],a[i][M-j+1]);
}

int main()
{
    scanf("%d%d",&N,&M);
    for(int i=1;i<=N;i++)
        for(int j=1;j<=M;j++){
            scanf("%d",&a[i][j]);
            maxa=max(maxa,a[i][j]);mina=min(mina,a[i][j]);
        }
    flip2();
    ans=Solve();
    flip1();ans=min(ans,Solve());
    flip2();ans=min(ans,Solve());
    flip2();ans=min(ans,Solve());
    printf("%d\n",ans);
    return 0;
}

 

posted @ 2017-10-23 09:00  Elfish?  阅读(292)  评论(0编辑  收藏  举报