详细算法解析看 王知昆-浅淡用极大化思想解决最大子矩形问题
题目:牛奶浴场
https://www.luogu.org/problemnew/show/P1578#sub
算法1:dp悬线。。。
详见动态规划汇总 20题
此算法适合点比较密集的题
此题因30000*30000会爆。。。
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxSize=30000;
int L,W;
bool a[maxSize+5][maxSize+5];
int h[2][maxSize+5],l[2][maxSize+5],r[2][maxSize+5];
//h[] l[] r[] 表示坐标
int find1(int x,int y)//向左找最近障碍点
{
int i;
for (i=y-1;i>0;i--)
{
if (a[x][i]==1)
break;
}
return i;
}
int find2(int x,int y)//向右找最近障碍点
{
int i;
for (i=y+1;i<W;i++)
{
if (a[x][i]==1)
break;
}
return i;
}
void dp()
{
int i,j,maxs,l1,r1,i0,i1,temp;
maxs=0;
i0=1; i1=0;
for (i=1;i<=L;i++)
{
temp=i0;//滚动数组
i0=i1;
i1=temp;
for (j=0;j<=W;j++)
{
if (a[i1][j]==1)
continue;
else if (a[i0][j]==1)
{
h[i1][j]=1;
l[i1][j]=0; r[i1][j]=W;
}
else if (a[i0][j]==0)
{
h[i1][j]=h[i0][j]+1;
l1=find1(i0,j); r1=find2(i0,j);
l[i1][j]=max(l1,l[i0][j]);
r[i1][j]=min(r1,r[i0][j]);
}
maxs=max(maxs,h[i1][j]*(r[i1][j]-l[i1][j]));
}
}
printf("%d\n",maxs);
}
int main()
{
int i,n,x,y;
freopen("a.txt","r",stdin);
scanf("%d%d",&L,&W);
scanf("%d",&n);
memset(a,0,sizeof(a));
memset(h,0,sizeof(h));
memset(l,0,sizeof(l));
memset(r,0,sizeof(r));
for (i=0;i<n;i++)
{
scanf("%d%d",&x,&y);
a[x][y]=1;
}
for (i=0;i<=W;i++)//初始化
{
l[0][i]=0;
r[0][i]=W;
}
dp();
return 0;
}
算法2:极大化思想
此算法适合点比较稀疏的题
此题点<=5000个
完美√
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
struct node
{
int x,y;
};
const int maxSize=5000;
int L,W,n;
node N[maxSize+5];
bool compare2(node x,node y)
{
if (x.x==y.x)
return x.y<y.y;
else
return x.x<y.x;
}
bool compare1(node x,node y)
{
if (x.y==y.y)
return x.x<y.x;
else
return x.y<y.y;
}
int main()
{
int i,up,down,maxs,j;
freopen("a.txt","r",stdin);
scanf("%d%d",&L,&W);
scanf("%d",&n);
N[0].x=0; N[0].y=0;
N[n+1].x=L; N[n+1].y=W;
for (i=1;i<=n;i++)
scanf("%d%d",&N[i].x,&N[i].y);
sort(N,N+n+2,compare1);
maxs=0;
for (i=1;i<=n;i++)//从左向右扫
{
up=0; down=L;
for (j=i+1;j<=n+1;j++)
{
if (N[i].y==N[j].y)
continue;
maxs=max(maxs,(N[j].y-N[i].y)*(down-up));
if (N[j].x>N[i].x)
down=min(down,N[j].x);
else if (N[j].x<N[i].x)
up=max(up,N[j].x);
else
break;
}
}
for (i=n;i>=1;i--)//从右向左扫
{
up=0; down=5;
for (j=i-1;j>=0;j--)
{
if (N[i].y==N[j].y)
continue;
maxs=max(maxs,(N[i].y-N[j].y)*(down-up));
if (N[j].x>N[i].x)
down=min(down,N[j].x);
else if (N[j].x<N[i].x)
up=max(up,N[j].x);
else
break;
}
}
sort(N,N+n+2,compare2);
for (i=0;i<=n;i++)//纵向扫盲
{
maxs=max(maxs,(N[i+1].x-N[i].x)*W);
}
printf("%d\n",maxs);
return 0;
}