我叫张小黑
张小黑的挣扎生活
posts - 66,  comments - 109,  trackbacks - 0

这道题是zp推荐的,说是一道动态规划题,做完后觉得这就是我最不认为是dp的一种dp题,他的思想和那种给你一个地图,起始位置在左上角,终点位置在右下角,每个位置上都有一定的宝藏,规定了每次只能往右走一步,或是往下走一步。。然后问你最后能取得的宝藏最大值,开始我就不认为这种题是dp,他的状态只会和前一状态有关。而1029这个题就是这样子的。

下面是我做这个题之前别人的提示,有几个关键字:
2^n个状态,n为列数,我们做到按行更新,更新一行的时候我们按列来,如果更新到最后一列,则换下一行。
更新当前行时和上一行有关。

这两句话给了开始的模糊印象。。但是确实有点抽象

下面是cpg2001  

用横线来划分阶段,对于图一,虽然划分后很整齐,但把某些砖分成了两半,于是将他们也添加进来,于是变成了图二,其显得参差不齐,但最多也是向下突出一格,在图三中,我们将图二的空隙填满,则又转移到了下一种状态。

定义添砖小块状态为1,否则为0,则每行状态可以映射到一个数(0,2^h})于是可建立这样的状态a[ i j]:表示第i行填满,第i+1行对应状态为j时的不同方案数,a[I,j]=a[i-1,k],其中,状态k可导出状态j,初始化条件a[0,0]=1,最后a[w,0]即为所求。


的启发,再加上zp的讲解逐渐清晰起来:
行数我们默认是从0开始


第三行的赋值情况 :000011
第四行的赋值情况 :100100
第五行的赋值情况 :011000
图一:第三行填满了,第三行的第一个格子是一个竖形格子,这个竖形格子的上格子在第三行,下格子在第四行,于是在第四行需要补格子故置为1,第三行的第二个第三个格子是个横条,我们都置为0,紧接着又是一个竖形格子的上半个格子,同样是0,下面两个都是竖形格子的下半个置为1
同理将分别对第四行第五行赋值
比如图二的第四行,第二第三个两个连续的零,还有一种方案是摆一个横条。
其他的详见注释。

我的代码:
#include<iostream>
#define max(a,b) (a
>b?a:b)
int N,M,maxl=0;
__int64 ans[
3000],tmp[3000];
void solve(
int j,int last,int now)
{
    
if(j>M)
    {
        tmp[
now]+=ans[last];
        maxl
=max(maxl,now);
        return;
    }
    
int up=(1<<(M-j))&last,uprt;
    
//up-->头顶上的那个格子状态,uprt-->头顶上的右边的那个格子的状态
    
if(j==M)
    {
        
if(!up)solve(j+1,last,now*2+1);//就剩一个空了,并且上面的那个是0,那么显然是竖条
        
//这一行需要补一个小方格
        
//如果上面是1,显然下面仍然是要接着一个竖条,但是这个小方格是上面这半个,无需置1
        
else solve(j+1,last,now*2);
    }
    
else
    {
        uprt
=(1<<(M-j-1))&last;
        
if(!up)
        {
            solve(j
+1,last,now*2+1);
            
if(!uprt)//如果头顶上的不为0,头顶上右边的也不为0,下面的就可以放一个横条
                solve(j
+2,last,now*4);
        }
        
else//这个地方时很容易出错的,我这里认为是第j列置为0
            
//可以理解为是一个竖形条状的上半个格子,也可以认为是一个横行条状的左半个格子
            
//这里千万不能把这两种情况分开计算,这样会重复的
            solve(j
+1,last,now*2);
    }
}
            

int main()
{
    
int i,j;
    
while(scanf("%d%d",&N,&M)&&N)
    {
        
if((N*M)%2)
        {
            printf(
"0\n");
            continue;
        }
        memset(ans,
0,sizeof(ans));
        ans[
0]=1;
        
for(i=1;i<=N;i++)
        {
            memset(tmp,
0,sizeof(tmp));
            
for(j=0;j<=maxl;j++)
                
if(ans[j])solve(1,j,0);
            memcpy(ans,tmp,sizeof(tmp));
        }
        printf(
"%I64d\n",ans[0]);
    }
    return 
0;
}
posted on 2008-07-08 14:01 zoyi 阅读(782) 评论(2)  编辑 收藏 引用 所属分类: acm动态规划

FeedBack:
# re: eoj 1029 走道铺砖
2008-07-08 14:30 | ecnu_zp
沙发~ ^_^
羡慕菠菜啊..
又漂亮又聪明....  回复  更多评论
  
# re: eoj 1029 走道铺砖
2009-05-23 15:02 | 大师傅啥的
zp是张朋哈  回复  更多评论
  

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


欢迎光临 我的白菜菜园

<2008年7月>
293012345
6789101112
13141516171819
20212223242526
272829303112
3456789

常用链接

留言簿(8)

随笔分类

随笔档案

文章档案

相册

acmer

online judge

队友

技术

朋友

搜索

  •  

最新评论

阅读排行榜

评论排行榜