poj1038(状态压缩)

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.总结,这个程序写了不是很久,结果是调试了很久。

 其中最主要的是使用了嵌套递归,全局变量,还发生共享变量的情况

解决方案:尽量少使用全局变量,有多个递归子程序时检查是否有发生变量共享的情况!

忘记递归边界的状态处理:写程序前仔细检查!

用错变量:变量命名更加合理!



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值