1.资料请参考刘汝佳黑书139页,注意行和列是反的,还有Qi=Pi-1(Pi>0) ,Qi=0 (Pi=0)这个转移是在不考虑当前行的芯片放置的转移,还有3种情况的描述好像有问题,最后是和队友一同讨论形成自己的思路,其实这三种情况大家自己去考虑一下应该也是好理解的。
2.黑书上的逐行递推+滚动数组
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
using namespace std;
#define M 15
#define N 155
#define STATE 177150//3^11
bool mat[M][N];//第0列为障碍!0为空,2为障碍
int d[2][STATE];//第n列的最大值 ans=max{d[n&1,state]}
int p[M];//3^0,3^1,……3^row-1
int bit[M];//保存解压后的状态
int state[2][STATE];
int row,col;
void init(int row,int col,int k)
{
memset(mat,0,sizeof(mat));
memset(d,0,sizeof(d));
for(int i=0; i<k; i++)
{
int r,c;
cin>>c>>r;
mat[r-1][c]=true;
}
for(int i=0; i<=col; i++)mat[row][i]=true;
for(int i=0; i<=row; i++)
{
mat[i][0]=true;//!!人为的添加左下边界,避免后面的讨论
}
}
void decode(int state)//状态解压
{
for(int i=0; i<=row; i++)
{
bit[i]=state%3;
state/=3;
}
}
int curState;//当前行状态
int cur,next;//当前列和下一列在滚动数组中的下标
int column;//当前列
void dfs(int nextState,int r,int cnt)
{
if(r>row-2)
{
//由当前状态产生出下一个状态nextState
int t;
if(mat[r][column])t=2;
else t=bit[r]?bit[r]-1:0;
nextState+=t*p[r];//有可能r=row-1
if(r<row)nextState+=2*p[row];//有可能r=row
int tmp=cnt+d[cur][curState];
if(!d[next][nextState])state[next][++state[next][0]]=nextState;
d[next][nextState]=d[next][nextState]>tmp?d[next][nextState]:tmp;
}
else
{
if(bit[r]==0&&bit[r+1]==0&&mat[r][column]==0&&mat[r+1][column]==0)
{
dfs(nextState+2*(p[r]+p[r+1]),r+2,cnt+1);//!!case 1
}
if(bit[r]<=1&&bit[r+1]<=1&&bit[r+2]<=1&&mat[r][column]==0&&mat[r+1][column]==0&&mat[r+2][column]==0)
{
dfs(nextState+2*(p[r]+p[r+1]+p[r+2]),r+3,cnt+1);//!!case 2
}
int t;
if(mat[r][column])t=2;
else t=bit[r]?bit[r]-1:0;
dfs(nextState+t*p[r],r+1,cnt);//!!case 3
}
}
void dp()
{
p[0]=1;
for(int i=1; i<=row; i++)p[i]=3*p[i-1];
int s=0;
for(int i=0; i<=row; i++)
{
if(mat[i][1])s+=2*p[i];
else s+=p[i];
}
state[0][0]=0;
state[0][++state[0][0]]=s;//置初使状态
for(int i=2; i<=col; i++)
{
column=i;
cur=i&1;
next=(cur+1)&1;
state[next][0]=0;
memset(d[next],0,sizeof(d[next]));
for(int j=1; j<=state[cur][0]; j++)//遍历当前行的每一个状态
{
curState=state[cur][j];
decode(curState);
dfs(0,0,0);
}
}
}
int main()
{
// freopen("data.in","r",stdin);
int Case;
cin>>Case;
while(Case--)
{
int k;
cin>>col>>row>>k;
//!!注意由于习惯问题,程序中的行和列和问题中的行列是相反的
//!!问题中的行1,2……N相当于程序中的列1,2,……col
//!!问题中的列1,2……M相当于程序中的列0,1,2……row-1
//!!添加的左边界为mat[i][0]i>=0,i<=row;
//!!添加的下边界为mat[row][i]i>=0,i<=col;
init(row,col,k);
dp();
int ans=0;
for(int i=0; i<STATE; i++)ans=max(ans,d[(col+1)&1][i]);
cout<<ans<<endl;
}
}
3.其实之前是用暴力写的还没有滚动数组,直接就超了内存,也附上吧,以示警戒!
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
using namespace std;
#define M 15
#define N 155
#define STATE 177150
bool mat[M][N];//第0列为障碍!0为空,2为障碍
int d[N][STATE];//第n列的最大值ans=max{d[n,state]}
int p[M];//3^0,3^1,……3^row-1
int row,col;
void init(int row,int col,int k)
{
memset(mat,0,sizeof(mat));
memset(d,0,sizeof(d));
for(int i=0; i<k; i++)
{
int r,c;
cin>>c>>r;
mat[r-1][c]=true;
}
for(int i=0;i<=col;i++)mat[row][i]=true;
for(int i=0; i<=row; i++)
{
mat[i][0]=true;//!!左下边界
}
}
inline int getbit(int state,int i)
{
return (state%p[i+1])/p[i];
}
void dfs(int layer,int nextState);
void bruteForce(int column,int curState,int nextState,int r,int cnt)
{
if(r>row-2)//!!
{
int t,bit1=getbit(curState,r);//row或者是row-1
if(mat[r][column])t=2;
else t=bit1?bit1-1:0;
nextState+=t*p[r];
if(r<row)nextState+=2*p[row];
int tmp=cnt+d[column][curState];
if(d[column+1][nextState]>0)
{
if(d[column+1][nextState]<tmp)
{
d[column+1][nextState]=tmp;
dfs(column+1,nextState);
}
}
else
{
d[column+1][nextState]=tmp;
dfs(column+1,nextState);
}
}
else
{
int bit1=getbit(curState,r),bit2=getbit(curState,r+1),bit3=getbit(curState,r+2);
if(bit1==0&&bit2==0&&mat[r][column]==0&&mat[r+1][column]==0)
{
bruteForce(column,curState,nextState+2*(p[r]+p[r+1]),r+2,cnt+1);
}
if(bit1<=1&&bit2<=1&&bit3<=1&&mat[r][column]==0&&mat[r+1][column]==0&&mat[r+2][column]==0)
{
bruteForce(column,curState,nextState+2*(p[r]+p[r+1]+p[r+2]),r+3,cnt+1);
}
int t;
if(mat[r][column])t=2;
else t=bit1?bit1-1:0;
bruteForce(column,curState,nextState+t*p[r],r+1,cnt);
}
}
void dfs(int column,int curState)
{
if(column>col)return;
bruteForce(column,curState,0,0,0);
}
int main()
{
// freopen("data.in","r",stdin);
int Case;
cin>>Case;
while(Case--)
{
int k;
cin>>col>>row>>k;
init(row,col,k);
p[0]=1;
for(int i=1; i<=row+2; i++)p[i]=3*p[i-1];
int s=0;
for(int i=0; i<=row; i++)
{
if(mat[i][1])s+=2*p[i];
else s+=p[i];
}
dfs(2,s);
int ans=0;
for(int i=0; i<STATE; i++)ans=max(ans,d[col+1][i]);
cout<<ans<<endl;
}
}
3.总结,这个程序写了不是很久,结果是调试了很久。
其中最主要的是使用了嵌套递归,全局变量,还发生共享变量的情况
解决方案:尽量少使用全局变量,有多个递归子程序时检查是否有发生变量共享的情况!
忘记递归边界的状态处理:写程序前仔细检查!
用错变量:变量命名更加合理!