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 2021-11-03 21:40  eleveni  阅读(60)  评论(0)    收藏  举报