程序设计II上机实验10B:"完美阴阳矩阵"
2017-07-14

“完美阴阳矩阵”

Time limit: 1000 ms

Memory limit: 256 MB

Standard I/O

Content

Input Description

输入的第一行是两个空格隔开的整数n和m,分别表示矩阵的长和宽。接下来的n行,每行m个数,空格隔开,表示一个n×m的阴阳矩阵。

Output Description

两行,每行一个数,表示所求答案。

Sample

INPUT

3 3
1 0 1
0 1 0
1 0 0

OUTPUT

4
6

Hint

对于20%20%的数据,n,m≤80n,m≤80

对于40%40%的数据,n,m≤400n,m≤400

对于100%100%的数据,n,m≤2000n,m≤2000(各种暴力方法都会超时哦)

Code

#include <stdio.h>
#include <stdlib.h>
typedef struct intervaldata{
    int begin;
    int end;
    struct intervaldata *next;
}Interval;//区间
Interval** allhead;
int m,n;
int MaxSquareLen,MaxRectArea;//最大方阵的边长,最大矩阵的面积()
int max(int a,int b){
    return a>b?a:b;
}
int min(int a,int b){
    return a<b?a:b;
}
Interval* MakeNode(int begin,int end){
    Interval* p=(Interval*)malloc(sizeof(Interval));
    p->begin=begin;
    p->end=end;
    p->next=NULL;
    return p;
}
void UpdateMaxRectArea(int weith,int depth){//更新矩阵最大值,注意到阴阳矩阵应该比普通矩阵长宽各+1
    MaxRectArea=max(MaxRectArea,(weith+1)*(depth+1));
    MaxSquareLen=max(MaxSquareLen,min(weith,depth)+1);
}
int Search(int row,int left,int right,int depth){//row是当前行
    //depth表示当前矩形纵深高度(占的行数,不包括当前行)
    //left,right是上一行传递下来的区间范围
    if(row>=m-1){//超出地图了,地图最后一行是m-2(全地图化为普通矩阵后共m-1行);
        UpdateMaxRectArea(right-left+1,depth);
        return 1;
    }
    Interval* p=allhead[row]->next;
    int tmpleft,tmpright;
    while(p!=NULL){
        if(p->end<left){
                p=p->next;
                continue;
        } 
        if(p->begin>right) break;
        tmpleft=max(left,p->begin);
        tmpright=min(right,p->end);
        Search(row+1,tmpleft,tmpright,depth+1);
        p=p->next;
    }
    //结算
    UpdateMaxRectArea(right-left+1,depth);
    return 1;
}
int main(){
    int i,j;
    scanf("%d%d",&m,&n);
    int **map=(int **)malloc(sizeof(int *)*m);
    for(i=0;i<m;i++){
        map[i]=(int *)malloc(sizeof(int)*n);
        for(j=0;j<n;j++){
            scanf("%d",&map[i][j]);
        }
    }
    allhead=(Interval**)malloc(sizeof(Interval*)*(m-1));//每一行的头结点指针
    for(i=0;i<m-1;i++){//化为普通0/1矩阵,同时求出每行的值为1区间存在链表里,问题化为求解最大1矩阵面积
        int start=-1;
        allhead[i]=MakeNode(0,0);//头结点不用
        Interval* now=allhead[i];
        for(j=0;j<n-1;j++){
            if(map[i][j+1]==!map[i][j] && map[i+1][j]==!map[i][j] && map[i+1][j+1]==map[i][j]){
                map[i][j]=1;
                if(start==-1) start=j;
            }
            else{
                map[i][j]=0;
                if(start!=-1){
                    Interval* p=MakeNode(start,j-1);
                    now->next=p;
                    now=p;
                    start=-1;
                }
            }
        }
        if(start!=-1){
            Interval* p=MakeNode(start,j-1);
            now->next=p;
        }
    }
    for(i=0;i<m-1;i++){//遍历每一行的区间
        Interval* p=allhead[i]->next;
        while(p!=NULL){
            Search(i+1,p->begin,p->end,1);
            p=p->next;
        }
    }
    printf("%d\n%d",MaxSquareLen*MaxSquareLen,MaxRectArea);
    for(i=0;i<m;i++){
        free(map[i]);
    }
    free(map);
    for(i=0;i<m-1;i++){
        Interval* p=allhead[i];
        while(p!=NULL){
            allhead[i]=p->next;
            free(p);
            p=allhead[i];
        }
    }
    return 0;
}
搜索
背景设置