题意:给你一个矩阵,每一个小格都有一个字母表示它的值( ′0′∼′9′ ),让你横着切三刀,纵着切三刀。把一个矩阵分成16个小矩阵,你会得到16个矩阵的最小的权值,问最小的权值最大为多少。
分析:由于矩阵最大为75*75,但是如果直接枚举切的方式,肯定会超时,但是我们可以折半枚举,只枚举横着切的方式,然后预处理出每一列的前缀和,通过二分的方式,二分最小值,计算最后的答案。
#include <bits/stdc++.h>
using namespace std;
class ChocolateDividingHard
{
public :
int sum[110][110];
int num[5][110];
int n,m;
int ans ;
bool Judge(int ss)
{
int sum1= 0,sum2 = 0,sum3 = 0,sum0 = 0;
int pos = 0;
for(int i = 0;i<m;i++)
{
sum0+= num[0][i];
sum1 += num[1][i];
sum2 += num[2][i];
sum3 += num[3][i];
if(sum0 >= ss && sum1 >= ss && sum2 >= ss &&sum3 >= ss)
{
sum0 = sum1 = sum2 = sum3 = 0;
pos++;
}
if(pos >= 4) return true;
}
return pos >= 4;
}
int Ok(int st1,int st2,int st3)//二分答案
{
for(int i = 0;i < m;i++)
{
num[0][i] = sum[st1][i];
num[1][i] = sum[st2][i] - sum[st1][i];
num[2][i] = sum[st3][i] - sum[st2][i];
num[3][i] = sum[n][i] - sum[st3][i];
}
int l = 0,r = 90000;
int ac = 0 ;
while(l <= r)
{
int mid = (l+r) >>1;
if(Judge(mid))
{
ac = mid;
l = mid + 1;
}
else r = mid - 1;
}
return ac;
}
void solve()
{
ans = 0;
for(int i = 1;i <= n-1;i++)//枚举横着切的方式。
{
for(int j = i+1; j <= n-1 ;j++)
{
for(int k = j+1;k <= n-1;k++)
{
ans = max(ans,Ok(i,j,k));
}
}
}
}
int findBest(vector <string> chocolate)
{
n = chocolate.size();
m = chocolate[0].size();
memset(sum,0,sizeof(sum));
for(int i = 0;i<n;i++)//预处理出列前缀和
{
for(int j = 0 ;j<m;j++)
{
sum[i+1][j] = sum[i][j] + chocolate[i][j]-'0';
}
}
solve();
return ans;
}
};