題面
題意
給出一個矩陣,若一個矩陣中的所有元素都相同,則這個矩陣的代價爲0,反之可以將它分成兩個子矩陣,代價爲兩個子矩陣的代價的較大值+1.
做法
因爲答案是log級別的,所以可以考慮枚舉答案,記從第l行到第r行從第i列開始最多可以向右擴展到哪一列所形成的矩陣的代價爲當前答案,若,則表示當前答案即爲整個矩形的代價.
時的答案很好處理,考慮如何將此時的答案轉移到ans+1時的答案.一個矩形有兩種拼接方法:
1.兩個所在行相同的相鄰矩形,直接轉移:
2.兩個所在列相同的相鄰矩形,,這個可以通過二分找到最優解.
代碼
#include<bits/stdc++.h>
#define N 200
using namespace std;
int m,n,ans,dp[2][N][N][N];
char mm[N][N];
bool now,cur;
inline void Max(int &u,int v){if(v>u) u=v;}
int main()
{
int i,j,p,q,l,r,mid;
cin>>m>>n;
for(i=1;i<=m;i++) scanf("%s",mm[i]+1);
now=1;
for(q=1;q<=m;q++)
{
for(p=q;p>=1;p--)
{
for(i=n;i>=1;i--)
{
if(p==q)
{
if(i==n) dp[now][p][q][i]=n+1;
if(mm[p][i]==mm[p][i+1]) dp[now][p][q][i]=dp[now][p][q][i+1];
else dp[now][p][q][i]=i+1;
}
else
{
if(mm[q-1][i]==mm[q][i]) dp[now][p][q][i]=min(dp[now][p][q-1][i],dp[now][q][q][i]);
else dp[now][p][q][i]=i;
}
}
}
}
for(ans=0;;ans++)
{
if(dp[now][1][m][1]==n+1)
{
cout<<ans;
return 0;
}
swap(now,cur);
for(p=1;p<=m;p++)
{
for(q=p;q<=m;q++)
{
for(i=1;i<=n;i++)
{
if(dp[cur][p][q][i]==n+1) dp[now][p][q][i]=n+1;
else dp[now][p][q][i]=dp[cur][p][q][dp[cur][p][q][i]];
for(l=p,r=q;l<r;)
{
mid=((l+r)>>1);
Max(dp[now][p][q][i],min(dp[cur][p][mid][i],dp[cur][mid+1][q][i]));
if(dp[cur][p][mid][i]>dp[cur][mid+1][q][i]) l=mid+1;
else r=mid;
}
}
}
}
}
}