poj Tony’s Tour (插头DP处女作--楼教主男(难)人八题之一)

/*
//题目链接:http://poj.org/problem?id=1739

acm记忆:在很久很久以前 ,当插头DP还只是被称作“基于连通性状态压缩动态规划”的时候,楼教主就将其化为男人八题 之列 !引得无数自认为很man的英雄豪杰欲AC之 而后快 !而吾等菜鸟是这学期才听闻 到还有插头DP一说 ,故欲快速刷之以解心中愁!遂捧着cdq(性别 :女)关于基于连通性状态压缩动态规划的论文研读数遍 ,别人一女生在论文里讲得貌似很简单,简单而我这个男生却看得 我神乎其神 !纠结数日不得解!思己既然 选择了做男人,那还是 要男人一会,所以不想去看这题 的解题报告,后放下 男人八题 ,在Timus的oj上 找到了需要用插头DP算法解决的 Formular1题,将各大神牛的代码结合 起来研读数日,终领会其精髓果断重拾 男人八题,可悲剧的是编码花了2小时,调试用 了哥哥一天的时间才AC,囧囧囧囧!在攻插头DP的过程中,多次都有认为自己 不像男人,但最终AC之后,才感觉重新做回了男人 !

 题目大意:在一个有阻碍点的矩阵里,从一个固定的点,到另一个固定点,将所以非阻碍点都遍历一遍的哈密顿通路的条数!
提示:DFS或BFS等搜索类方法,最坏的情况3的64次方,超时是必须的,所以不用想了!

此题难点是 :
1.关于每个点都有九个状态 ,要清晰地知道每个新状态的得到,应该对应于那几个原状态的!
2.换行的时候,最左边插头一定要等于0才能转移到下一行
3.还有就是此题和 Formular1不同的是,这题没有回路,所以“()“状态是不存在的(坑了我很久)!故此题只有8个状态!
4.最后就是:这里每个插头边有三种情况,所以用三进制的int型来表述每个插头的状态!

第一次接触此类题,所以代码的优化度不高!被我写了两百多行(貌似大神的也短不到哪儿去 ,嘿嘿) 废话不说那么多了,AC代码伺候 :
*/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define LL __int64
int hash[2][20005];
int state[2][20005];
LL dp[2][20005];
int  cnt[2];
int jz3[9];
inlineint get(ints, int pos)
{
 returns/jz3[pos]%3;
}
inlineint add(ints,int pos,int flag1,intflag2)
{
 returns+(flag1-s/jz3[pos]%3)*jz3[pos]+(flag2-s/jz3[pos+1]%3)*jz3[pos+1];
}
inlineint change(ints,int pos,int flag)
{
 returns+(flag-s/jz3[pos]%3)*jz3[pos];
}
inlinevoid  clear(intnow)
{
 memset(dp[now],0,sizeof(dp[now]));
 memset(hash[now],0,sizeof(hash[now]));
 cnt[now]=0;
}
int can(int s,intm)
{
 inti,flag,sum=0;
 for(i=0;i<=m;i++)
 {
  flag=s%3;
  s/=3;
  if(flag==1)sum++;
  if(flag==2)sum--;
  if(sum<0)break;
 }
 if(sum)return 0;
 elsereturn 1;
}
int main()
{
 intn,m,i,j,k,u,pre,now,col,raw,news,sum,mark,right;
 LL ans;
 charmap[9][9];
 for(jz3[0] = 1, i = 1; i < 9; i++) jz3[i] = jz3[i - 1] * 3;
 while(scanf("%d%d%c",&n,&m,&map[0][0])&&(m||n))
 {
  for(i = 1; i <= n; i++)
  {
   for(j = 1; j <= m; j++)
   {
    scanf("%c", &map[i][j]);
   }
   scanf("%c",&map[0][0]);
  }
  if(n==1||m==1)
   printf("0n");
  else
  {
   pre = 0, now = 1; clear(now),dp[now][0] = 1, cnt[now] = 1, state[now][cnt[now]] = 0, hash[now][0] = 1;
   for(i = 1; i <= n; i++)
   {
    for(pre = !pre, now = !now, clear(now), j = 1; j <= cnt[pre]; j++ )
    {
     if( (get(state[pre][j], m) == 0) &&((i==1)||state[pre][j])) 
     {
      news=state[pre][j] * 3;
      if(can(news,m))
      {
       state[now][++cnt[now]]=news;
       hash[now][news] = 1; 
       dp[now][news] = dp[pre][state[pre][j]];
      }
     }
    }
      
    for(j = 1;j <= m;j++)
    {
     pre = !pre, now = !now, clear(now);
     for(k = 1; k <= cnt[pre]; k++)
     {
      col = get(state[pre][k],j-1), raw = get(state[pre][k],j);
      if(map[i][j] =='#')
      {
       if(!(col||raw))
       {
        dp[now][state[pre][k]] += dp[pre][state[pre][k]];
        if(!hash[now][state[pre][k]]) state[now][++cnt[now]] = state[pre][k], hash[now][state[pre][k]] = 1;
       }
      }
      else
      {
       if(!(col||raw))
       {
        news = add(state[pre][k], j-1, 1, 2);
        if(can(news,m))
        {
         dp[now][news] += dp[pre][state[pre][k]];
         if(!hash[now][news]) state[now][++cnt[now]] = news, hash[now][news] = 1;
        }
       }
       elseif(col==0&&raw==1)
       {
        dp[now][state[pre][k]] += dp[pre][state[pre][k]];
        if(!hash[now][state[pre][k]]) state[now][++cnt[now]] = state[pre][k], hash[now][state[pre][k]] = 1;
        news = add(state[pre][k], j-1, 1, 0);
        if(can(news,m))
        {
         dp[now][news] += dp[pre][state[pre][k]];
         if(!hash[now][news]) state[now][++cnt[now]] = news, hash[now][news] = 1;
        }
       }
       elseif(col==1&&raw==0)
       {
        dp[now][state[pre][k]] += dp[pre][state[pre][k]];
        if(!hash[now][state[pre][k]]) state[now][++cnt[now]] = state[pre][k], hash[now][state[pre][k]] = 1;
        news = add(state[pre][k], j-1, 0, 1);
        if(can(news,m))
        {
         dp[now][news] += dp[pre][state[pre][k]];
         if(!hash[now][news]) state[now][++cnt[now]] = news, hash[now][news] = 1;
        }
       }
       elseif(col==0&&raw==2)
       {
        dp[now][state[pre][k]] += dp[pre][state[pre][k]];
        if(!hash[now][state[pre][k]]) state[now][++cnt[now]] = state[pre][k], hash[now][state[pre][k]] = 1;
        news = add(state[pre][k], j-1, 2, 0);
        if(can(news,m))
        {
         dp[now][news] += dp[pre][state[pre][k]];
         if(!hash[now][news]) state[now][++cnt[now]] = news, hash[now][news] = 1;
        }
       }
       elseif(col==2&&raw==0)
       {
        dp[now][state[pre][k]] += dp[pre][state[pre][k]];
        if(!hash[now][state[pre][k]]) state[now][++cnt[now]] = state[pre][k], hash[now][state[pre][k]] = 1;
        news = add(state[pre][k], j-1, 0, 2);
        if(can(news,m))
        {
         dp[now][news] += dp[pre][state[pre][k]];
         if(!hash[now][news]) state[now][++cnt[now]] = news, hash[now][news] = 1;
        }
       }
       elseif(col==2&&raw==1)
       {
        news = add(state[pre][k], j-1, 0, 0);
        if(can(news,m))
        {
         dp[now][news] += dp[pre][state[pre][k]];
         if(!hash[now][news]) state[now][++cnt[now]] = news, hash[now][news] = 1;
        }
       }
       elseif(col==1&&raw==1)
       {
        sum=1;
        for(u = j + 1; u <= m; u++)
        {
         mark = get(state[pre][k],u);//这里的参数u原本被写成j了,是我花了几个小时一个一个状态的调试出来的,之伤感!
         if(mark==1)sum++;
         if(mark==2)sum--;
         if(!sum)break;
        }
        if(!sum)
        {
         news = add(state[pre][k], j-1, 0, 0);
         news=change(news, u, 1);
         if(can(news,m))
         {
          dp[now][news] += dp[pre][state[pre][k]];
          if(!hash[now][news]) state[now][++cnt[now]] = news, hash[now][news] = 1;
         }
        }
       }
       elseif(col==2&&raw==2)
       {
        sum=1;
        for(u = j -2; u >= 0; u--)
        {
         mark = get(state[pre][k],u);
         if(mark==1)sum--;
         if(mark==2)sum++;
         if(!sum)break;
        }
        if(!sum)
        {
         news = add(state[pre][k], j-1, 0, 0);
         news=change(news, u, 2);
         if(can(news,m))
         {
          dp[now][news] += dp[pre][state[pre][k]];
          if(!hash[now][news]) state[now][++cnt[now]] = news, hash[now][news] = 1;
         }
        }
       }
     }
    }
   }
  }
  ans=0,right=jz3[0]+2*jz3[m-1];
  for(j = 1; j <= cnt[now]; j++)
  {
   if(state[now][j]==right)
    ans+=dp[now][state[now][j]];
  }
  printf("%I64dn",ans);
  }
 }
 return0;
}
/*
3 2
..
..
..
2 2
..
..
2 3
#..
...
3 4
....
....
....
*/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值