luogu 1169 [ZJOI2007]棋盘制作 悬线dp

悬线法,虽然得不到局部最优解,但是一定能得到全局最优解的算法,十分神奇~ 

#include <cstdio> 
#include <algorithm> 
#define N 2003 
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std;  
int n,m,ans1,ans2;    
int v[N][N],l[N][N],r[N][N],up[N][N],len[N][N];           
int main() 
{  
    int i,j; 
    // setIO("input");  
    scanf("%d%d",&n,&m);   
    for(i=1;i<=n;++i) 
    {
        for(j=1;j<=m;++j)     
            scanf("%d",&v[i][j]),l[i][j]=r[i][j]=j, up[i][j]=1,len[i][j]=1;       
    }   
    for(i=1;i<=n;++i) 
    {
        for(j=2;j<=m;++j) if(v[i][j]!=v[i][j-1]) l[i][j]=l[i][j-1];     
        for(j=m-1;j>=1;--j) if(v[i][j]!=v[i][j+1]) r[i][j]=r[i][j+1];    
    }           
    for(i=1;i<=n;++i) 
    {      
        for(j=1;j<=m;++j) 
        {  
            if(i>1 && v[i][j]!=v[i-1][j]) 
            {      
                l[i][j]=max(l[i][j], l[i-1][j]);             
                r[i][j]=min(r[i][j], r[i-1][j]);  
                up[i][j]=up[i-1][j]+1;  
            }                  
            ans1=max(ans1, up[i][j]*(r[i][j]-l[i][j]+1));   
        }   
    }
    for(i=1;i<=n;++i) 
    {
        for(j=1;j<=m;++j) 
        {     
            if(i>1&&j>1&&v[i][j]!=v[i][j-1]&&v[i][j]!=v[i-1][j]&&v[i][j]==v[i-1][j-1])   
            {
                len[i][j]=min(len[i][j-1], min(len[i-1][j], len[i-1][j-1]))+1;  
                  
            }      
        }
    }
    for(i=1;i<=n;++i) 
    {
        for(j=1;j<=m;++j) ans2=max(ans2, len[i][j]*len[i][j]);    
    }
    printf("%d\n%d\n",ans2,ans1);   
    return 0; 
}

  

posted @ 2019-09-25 10:44  EM-LGH  阅读(142)  评论(0编辑  收藏  举报