版权声明:虽然本蒟蒻很菜,但各位dalao转载请注明出处谢谢。 https://blog.csdn.net/xuxiayang/article/details/85207987
大意
给定一个 的矩阵,其中一些点已经被覆盖,现在要用 的长方形去覆盖这个矩阵(可以90度翻转),问放到不能再放的最少长方形放置数。
数据范围:
对于30%的数据
对于100%的数据
思路
10%玄学
代码1
#include<algorithm>
#include<cstdio>
using namespace std;int n,m;
signed main()
{
freopen("cake.in","r",stdin);
freopen("cake.out","w",stdout);
scanf("%d%d",&n,&m);
printf("%d",max(n,m));
}
30%暴搜
代码2
#include<cstdio>
#include<iostream>
using namespace std;int n,m,ans=0x3f3f3f3f;
char c;
bool ok[71][9];
inline char Getchar()
{
static char buf[100000],*p1=buf+100000,*pend=buf+100000;
if(p1==pend)
{
p1=buf; pend=buf+fread(buf,1,100000,stdin);
if (pend==p1) return -1;
}
return *p1++;
}
inline bool check()
{
for(register int i=1;i<=n;i++)
for(register int j=1;j<=m;j++)
if(!ok[i][j])
if(!ok[i+1][j]||!ok[i][j+1]) return false;
return true;
}
inline void dfs(register int now,register int x,register int y)
//在线的 过程 深度优先搜索 (记录整型 当前使用的长方形个数,记录整型 当前是第几行,记录整型 当前是第几个)
{
if(now>=ans) return;//最优性剪枝
if(x==n&&y==m)
{
if(check())ans=now;//保存答案
return;
}
if(ok[x][y])//已被覆盖
{
if(y==m) dfs(now,x+1,1);//下一行
else dfs(now,x,y+1);//下一个
return;
}
ok[x][y]=true;//填充
if(!ok[x][y+1]&&y<m)//后面那格可以填
{
ok[x][y+1]=true;//填
dfs(now+1,x,y+1);
ok[x][y+1]=false;//回溯
}
if(!ok[x+1][y]&&x<n)//下面那格可以填
{
ok[x+1][y]=true;//填
if(y==m) dfs(now+1,x+1,1);
else dfs(now+1,x,y+1);//判断是否填到边界
ok[x+1][y]=false;
}
ok[x][y]=false;
if(ok[x-1][y]||ok[x][y-1])//可以空
{
if(y==m) dfs(now,x+1,1);//直接空掉这格
else dfs(now,x,y+1);
}
}
signed main()
{
freopen("cake.in","r",stdin);
freopen("cake.out","w",stdout);
cin>>n>>m;
for(register int i=1;i<=n;i++)
{
ok[i][0]=ok[i][m+1]=1;
for(register int j=1;j<=m;j++)
{
cin>>c;
ok[0][j]=ok[n+1][j]=1;//周围不能再填
if(c=='*') ok[i][j]=1;//标记
}
}
dfs(0,1,1);//搜索
cout<<ans;
}
我们发现这样的代码没有记忆化,于是乎我们就想到了记忆化,但是这样由于状态很多没法表示,于是就可以用状态压缩每一行,然后进行状压 (记忆化搜索)
AC代码
#include<cstdio>
#include<cstring>
#include<iostream>
#define ri register int
using namespace std;
int p[11],f[71][131][131],n,m;
char c;
int i,j,l,a[72],s,ans=0x3f3f3f3f;
inline void cge(ri k,ri x, ri y,ri z,ri t)
//在线的 过程 修改(当前填补的列数,上一行的状态,这一行的状态,下一行的状态,当前步数)
{
if(k>0&&((x&p[k-1])==0)&&((y&p[k-1])==0)) return;//若出现纵的两个空位,不合法,退出
if(k>1&&((y&p[k-1])==0)&&((y&p[k-2])==0)) return;//若出现横的两个空位,不合法,退出
if(k==m)//搜索完毕
{
f[i][y][z]=min(f[i][y][z],f[i-1][j][l]+t);//状态转移
return;
}
cge(k+1,x,y,z,t);//这一格不填
if(((z&p[k])==0)&&((y&p[k])==0))//能填纵的
cge(k+1,x,y|p[k],z|p[k],t+1);//这一行的和下一行的都要修改
if(k<m-1&&((y&p[k])==0)&&((y&p[k+1])==0))//能填横的
cge(k+2,x,y|p[k]|p[k+1],z,t+1);//修改这一行的两个值
}
signed main()
{
freopen("cake.in","r",stdin);
freopen("cake.out","w",stdout);
cin>>n>>m;
for(i=1;i<=n;i++)
{
int x=0;
for(j=1;j<=m;j++)
{
cin>>c;
x<<=1;
if(c=='*') x++;
}
a[i]=x;
}
memset(f,0x3f3f3f3f,sizeof(f));
p[0]=1;
for(i=1;i<10;i++) p[i]=p[i-1]<<1;
s=p[m]-1;
f[0][s][a[1]]=0;
for(i=1;i<=n;i++)
for(j=0;j<=s;j++)
for(l=0;l<=s;l++)
if(f[i-1][j][l]<0x3f3f3f3f)
cge(0,j,l,a[i+1],0);
for(i=0;i<=s;i++)
ans=min(ans,f[n][i][0]);
cout<<ans;
}