2021.11.03 悬线法
[P1169 ZJOI2007]棋盘制作 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
悬线法——这竟然是DP?!
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=4010;
int n,m,a[N][N],L[N][N],R[N][N],len[N],maxnL[N],minnR[N],maxn1,maxn2;
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')w=-1;
ch=getchar();
}
while(ch<='9'&&ch>='0'){
s=s*10+ch-'0';
ch=getchar();
}
return s*w;
}
int main(){
n=read();m=read();
//for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)L[i][j]=R[i][j]=j;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
a[i][j]=read();
if(a[i][j]!=a[i][j-1]&&j>1)L[i][j]=L[i][j-1];
else L[i][j]=j;
if(i==1)a[0][j]=a[i][j];
}
}
for(int i=1;i<=n;i++)
for(int j=m;j>=1;j--){
if(a[i][j]!=a[i][j+1]&&j<m)R[i][j]=R[i][j+1];
else R[i][j]=j;
}
/*cout<<"L "<<endl;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)cout<<L[i][j]<<" ";
cout<<endl;
}
cout<<"R "<<endl;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)cout<<R[i][j]<<" ";
cout<<endl;
}*/
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(a[i][j]==a[i-1][j])len[j]=1,maxnL[j]=L[i][j],minnR[j]=R[i][j];
else{
++len[j];
maxnL[j]=max(maxnL[j],L[i][j]);
minnR[j]=min(minnR[j],R[i][j]);
int k=min(len[j],minnR[j]-maxnL[j]+1);
maxn1=max(maxn1,k*k);
maxn2=max(maxn2,len[j]*(minnR[j]-maxnL[j]+1));
}
}
/*cout<<"maxnL "<<endl;
for(int j=1;j<=m;j++)cout<<maxnL[j]<<" ";cout<<endl;
cout<<"minnR "<<endl;
for(int j=1;j<=m;j++)cout<<minnR[j]<<" ";cout<<endl;
cout<<"len "<<endl;
for(int j=1;j<=m;j++)cout<<len[j]<<" ";cout<<endl<<endl;*/
}
cout<<maxn1<<endl<<maxn2;
return 0;
}
/*
3 3
0 0 0
0 1 0
0 0 0
ans 1 3
*/
与下面这一题在细节方面有区别:
P4147 玉蟾宫 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=1010;
int n,m,a[N][N],L[N][N],R[N][N],maxnL[N],minnR[N],len[N],ans;
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')w=-1;
ch=getchar();
}
while(ch<='9'&&ch>='0'){
s=s*10+ch-'0';
ch=getchar();
}
return s*w;
}
int main(){
n=read();m=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
char ch;//=getchar();
cin>>ch;
if(ch=='R')a[i][j]=1;
/*if(a[i][j-1]==0&&j>1)L[i][j]=L[i-1][j];
else L[i][j]=j;*/
if(a[i][j]==1||j==1)L[i][j]=j;
else{
if(a[i][j-1]==1)L[i][j]=j;
else L[i][j]=L[i][j-1];
}
a[0][j]=1;
}
for(int i=1;i<=n;i++)
for(int j=m;j>=1;j--){
/*if(a[i][j+1]==0&&j<m)R[i][j]=R[i][j+1];
else R[i][j]=j;*/
if(a[i][j]==1||j==m)R[i][j]=j;
else{
if(a[i][j+1]==1)R[i][j]=j;
else R[i][j]=R[i][j+1];
}
}
/*cout<<"L "<<endl;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)cout<<L[i][j]<<" ";
cout<<endl;
}
cout<<"R "<<endl;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)cout<<R[i][j]<<" ";
cout<<endl;
}*/
for(int i=0;i<=n;i++){
for(int j=1;j<=m;j++){
if(a[i][j]==1)len[j]=0,maxnL[j]=0,minnR[j]=0x3f3f3f3f;
else{
++len[j];
maxnL[j]=max(maxnL[j],L[i][j]);
minnR[j]=min(minnR[j],R[i][j]);
ans=max(ans,len[j]*(minnR[j]-maxnL[j]+1));
}
}
/*cout<<"maxnL "<<endl;
for(int j=1;j<=m;j++)cout<<maxnL[j]<<" ";cout<<endl;
cout<<"minnR "<<endl;
for(int j=1;j<=m;j++)cout<<minnR[j]<<" ";cout<<endl;
cout<<"len "<<endl;
for(int j=1;j<=m;j++)cout<<len[j]<<" ";cout<<endl<<endl;*/
}
cout<<ans*3;
return 0;
}
重点:
区别:
第一题是这一行即使不是上一行的接下来的数据,但有可能是接着下一行,所以,这一行的maxnL和 minnR要更新为(i,j)位上的L与R。第二题是这一行不是上一行接下来的数据,那就也不可能是接着下一行,所以这一个位置就相当于报废了,只要耐心等待合法位置的开始就行~具体请仔细区别两个代码的不同。
第一题同类型题:
土豪聪要请客
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=410;
int n,m,ans,L[N][N],R[N][N],len[N],maxnL[N],minnR[N],a[N][N];
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')w=-1;
ch=getchar();
}
while(ch<='9'&&ch>='0'){
s=s*10+ch-'0';
ch=getchar();
}
return s*w;
}
int main(){
//freopen("stol.in","r",stdin);
//freopen("stol.out","w",stdout);
//注意,最后还要减去他自己!!!
n=read();m=read();
for(int i=0;i<=n+1;i++)for(int j=0;j<=m+1;j++)a[i][j]=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
char ch;
cin>>ch;
if(ch=='.')a[i][j]=0;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
if(a[i][j]==1)L[i][j]=0;
else{
if(a[i][j-1]==1)L[i][j]=j;
else L[i][j]=L[i][j-1];
}
}
for(int i=1;i<=n;i++)
for(int j=m;j>=1;j--){
if(a[i][j]==1)R[i][j]=0;
else{
if(a[i][j+1]==1)R[i][j]=j;
else R[i][j]=R[i][j+1];
}
}
/*cout<<"L "<<endl;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)cout<<L[i][j]<<" ";
cout<<endl;
}
cout<<"R "<<endl;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)cout<<R[i][j]<<" ";
cout<<endl;
}
cout<<endl;*/
for(int i=0;i<=n;i++){
for(int j=1;j<=m;j++){
if(a[i][j]==1){
/*if(maxnL[j]!=0&&minnR[j]!=0x3f3f3f3f)
ans=max(ans,(len[j]+(minnR[j]-maxnL[j]+1))*2),
cout<<len[j]<<" "<<maxnL[j]<<" "<<minnR[j]<<endl;*/
len[j]=0,minnR[j]=0x3f3f3f3f,maxnL[j]=0;
}
else{
++len[j];
minnR[j]=min(minnR[j],R[i][j]);
maxnL[j]=max(maxnL[j],L[i][j]);
ans=max(ans,(len[j]+(minnR[j]-maxnL[j]+1))*2);
//cout<<len[j]<<" "<<maxnL[j]<<" "<<minnR[j]<<endl;
}
//if(i==n&&!a[i][j])ans=max(ans,(len[j]+(minnR[j]-maxnL[j]+1))*2);
}
/*for(int j=1;j<=m;j++)cout<<len[j]<<" ";cout<<endl;
for(int j=1;j<=m;j++)cout<<maxnL[j]<<" ";cout<<endl;
for(int j=1;j<=m;j++)cout<<minnR[j]<<" ";cout<<endl;
cout<<ans<<endl;*/
}
cout<<ans-1;
return 0;
}
/*
3 4
. . . .
. X X .
. . . .
ans 9
*/
/*
3 5
. X . X .
X . X . X
. X . X .
ans 3
*/
/*
4 7
X X . X X X X
X . . . . . X
X . . . . X X
X X X X . X X
ans 11
*/
DP的 写法:
P1681 最大正方形II - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=1510;
int n,m,a[N][N],f[N][N][2],ans;
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')w=-1;
ch=getchar();
}
while(ch<='9'&&ch>='0'){
s=s*10+ch-'0';
ch=getchar();
}
return s*w;
}
int main(){
n=read();m=read();
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)a[i][j]=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
int x=a[i][j];
f[i][j][x]=min(f[i-1][j-1][x],min(f[i-1][j][x^1],f[i][j-1][x^1]))+1;
ans=max(ans,max(f[i][j][x],f[i][j][x^1]));
//f[i][j]+=1;
}
cout<<ans;
return 0;
}
第二题同类型题:
[P2701 USACO5.3]巨大的牛棚Big Barn - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)[P2701 USACO5.3]巨大的牛棚Big Barn - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=1010;
int n,m,ans,a[N][N],L[N][N],R[N][N],maxnL[N],minnR[N],len[N];
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')w=-1;
ch=getchar();
}
while(ch<='9'&&ch>='0'){
s=s*10+ch-'0';
ch=getchar();
}
return s*w;
}
int main(){
n=read();m=read();
for(int i=1;i<=m;i++){
int u,v;
u=read();v=read();
a[u][v]=1;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
a[0][j]=1;
if(a[i][j]==1||j==1)L[i][j]=j;
else{
if(a[i][j-1]==1)L[i][j]=j;
else L[i][j]=L[i][j-1];
}
}
for(int i=1;i<=n;i++)
for(int j=n;j>=1;j--){
if(a[i][j]==1||j==n)R[i][j]=j;
else{
if(a[i][j+1]==1)R[i][j]=j;
else R[i][j]=R[i][j+1];
}
}
for(int i=0;i<=n;i++)
for(int j=1;j<=n;j++){
if(a[i][j]==1)len[j]=0,maxnL[j]=0,minnR[j]=0x3f3f3f3f;
else{
++len[j];
maxnL[j]=max(maxnL[j],L[i][j]);
minnR[j]=min(minnR[j],R[i][j]);
int k=min(len[j],minnR[j]-maxnL[j]+1);
ans=max(ans,k);
}
}
cout<<ans;
return 0;
}
DP的写法:
P1387 最大正方形 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=110;
int n,m,f[N][N][N],a[N][N],sum[N][N];
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')w=-1;
ch=getchar();
}
while(ch<='9'&&ch>='0'){
s=s*10+ch-'0';
ch=getchar();
}
return s*w;
}
inline int calc(int x,int y,int u,int v){
int tot=sum[u][v]-sum[x-1][v]-sum[u][y-1]+sum[x-1][y-1];
//cout<<x<<" "<<y<<" "<<u<<" "<<v<<" "<<tot<<" "<<(u-x+1)*(v-y+1)<<endl;
if(tot==(u-x+1)*(v-y+1))return 1;
else return 0;
}
int main(){
n=read();m=read();
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){
a[i][j]=read();
//if(a[i][j]==1)f[i][j][1]=1;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j];
/*(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)cout<<sum[i][j]<<" ";
cout<<endl;
}
cout<<endl;*/
int ans=0;
for(int i=1;i<=n;i++){
int flag=0;
for(int j=i;j<=n;j++){
for(int k=i;k<=m;k++){
if(calc(j-i+1,k-i+1,j,k)){
flag=1;
break;
}
}
if(flag)break;
}
if(flag)ans=i;
}
cout<<ans;
/*for(int i=2;i<=min(n,m);i++)
for(int j=i;j<=n;j++)
for(int k=i;k<=m;k++)
for(int h=1;h<=min(j,k);h++){
//if(calc())
}*/
return 0;
}
posted on
浙公网安备 33010602011771号