poj 1038 状态压缩

这道题还是比较基础的状态压缩dp,但有几个点还是要去注意一下,注意点代码的注释中已经给出来了。

//poj 1038 状态压缩dp
#include<stdio.h>
#include<cstdlib>
#include<istream>
#include<algorithm>
#include<vector>
#include<string.h>
#define mod 105225319
#define maxn 100000
using namespace std;
int dp[3][maxn];                          //0:表示前两个都没有;1:表示前第二个有,前一个没有:2:表示前一个有。
int N,M,K,man=1,map[165][15];

int cal(int q[])
{
   int i,j=1,ans=0;
   for(i=1;i<=M;i++)
   {
       ans+=max(q[i]-1,0)*j;
       j*=3;
   }
   return ans;
}

void transform_(int sta,int f[])
{
    int i,j=1;
    for(i=2;i<=M;i++)
        j*=3;
    for(i=1;i<=M;i++)
    {
       f[M-i+1]=sta/j;
       sta=sta%j;
       j/=3;
    }
    return;
}

void dfs(int row,int cow,int q[],int cnt)                       //注意这里的状态转移不能直接用dp[]=dp[]来进行,因为不满足后效性,因为搜索并不是按0-n的顺序进行的,因此dp[i]的值未必会是最终的值,在后面会发生改变。
{
    if(cow-1>M)                             
        return;
    int tt=cal(q);
    int qq[20];
    memset(qq,0,sizeof(qq));
    dp[row%2][tt]=max(dp[row%2][tt],cnt);
    dfs(row,cow+1,q,cnt);
    if(q[cow]==0&&q[cow+1]==0&&cow+1<=M&&!map[row][cow]&&row>=3&&!map[row][cow+1]&&!map[row-1][cow]&&!map[row-1][cow+1]&&!map[row-2][cow]&&!map[row-2][cow+1])
    {
        for(int i=1;i<=15;i++)
            qq[i]=q[i];
        qq[cow]=qq[cow+1]=3;
        dfs(row,cow+2,qq,cnt+1);
        memset(qq,0,sizeof(qq));
    }
    if(q[cow]<=1&&q[cow+1]<=1&&q[cow+2]<=1&&cow+2<=M&&row>=2&&!map[row-1][cow]&&!map[row-1][cow+1]&&!map[row-1][cow+2]&&!map[row][cow]&&!map[row][cow+1]&&!map[row][cow+2])
    {
        for(int i=1;i<=20;i++)
            qq[i]=q[i];
        qq[cow]=qq[cow+1]=qq[cow+2]=3;
        dfs(row,cow+3,qq,cnt+1);
        memset(qq,0,sizeof(qq));
    }
    return;
}

int main()
{
	int T, TT = 1;
	//freopen("d:\\in.txt","r",stdin);
	//freopen("d:\\inn.txt","w",stdout);
    scanf("%d",&T);
    while(T)
    {
       scanf("%d%d%d",&N,&M,&K);
       int i;
       memset(map,0,sizeof(map));
       memset(dp,-1,sizeof(dp));
       for(i=1;i<=K;i++)
       {
           int x,y;
           scanf("%d%d",&x,&y);
           map[x][y]=1;
       }
       man=1;
       for(i=1;i<=M;i++)
          man*=3;
       for(i=0;i<=man;i++)
        dp[0][i]=-1;
       dp[0][man-1]=0;
       for(i=1;i<=N;i++)
       {
            for(int jj=0;jj<=man;jj++)
                dp[i%2][jj]=-1;
           for(int s=0;s<man;s++)
           {
               if(dp[(i+1)%2][s]==-1)
                continue;
               int ds[20];
               memset(ds,0,sizeof(ds));
               transform_(s,ds);
              //printf("s=%d   i=%d\n",s,i);
               dfs(i,1,ds,dp[(i+1)%2][s]);
           }
       }
       int answ=0;
       for(i=0;i<man;i++)
           answ=max(dp[N%2][i],answ);
       printf("%d\n",answ);
       T--;
    }
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值