bzoj3125: CITY 题解

3125: CITY

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 486  Solved: 213
[Submit][Status][Discuss]

Description

小明和小华要参加NOI,踏上了去X市的火车。
小明望着窗外的田野,大楼,工厂缓缓后退,在思考着什么。
这时,对面的小华拿出手机对着他说:“看!我们在这个位置!”
小明望着手机上显示的地图,城市被接到分割成各个方块,而自己所在的点在慢慢移动。
他突然意识到自己甚至还没游历过这个自己所在的小城市,学校和家貌以及之间来回的道路似乎成了这个小城的唯一印象。
若我把它们全部走一圈,可能要仔细计划下吧……不,那么多方案,其实我应该早能做到了吧……小明在心里对自己说。
 

Input

第一行有两个数N, M表示地图被分割成N*M个块,接下来有N行,每行有M个字符。
 .  表示这个块可以通过
 - 表示这个块只可以左右通过
 | 表示这个块只可以上下通过
 # 表示这个块不能通过
(从每个块只能走到其上下左右相邻的四个块)
 

Output

一个数,表示小明把所以可以通过的块都经过且只经过一次并回到原地的方案数。
 

Sample Input

Sample 1
2 2
..
..


Sample 2
Input:
4 4
....
..-.
....
....

Sample Output

Output 1
1


Output 2
1

HINT

 

数据范围: 0 < N, M < 13 不保证答案在long 范围之内

 

Source

  联赛后第一次写题解……

  这道题可以说得上是插头DP裸题了,话说最早接触插头DP是在学基础状压的时候误打误撞看到了CDQ的论文,差点入坑,然而最后我还是得入一下。

  这道题比较特殊的就是‘-’ ‘|’这两个设定,但其实也很容易,我们只要在转移的时候进行特判,‘-’只能接左插头,‘|’只能接上插头。其余转移同理。但是要注意的是由于许多转移代码大体结构一样,可以直接复制粘贴,但是细节还是要去检查一下,我因为特判粘贴后位置改变却没发现调了两个小时。

  1 #include <iostream>
  2 #include <cstdlib>
  3 #include <cstdio>
  4 #include <cstring>
  5 #include <algorithm>
  6 #include <cmath>
  7 #define N 15
  8 using namespace std;
  9 int n,m,ma[N][N],zz,tot[1594330];
 10 char bb[N];
 11 int xp[N],b[1594330],dl[1594330];
 12 long long f[2][1594330],ans;
 13 bool check(int x,int t,int sum)
 14 {
 15     if(sum<0) return 0;
 16     if(x==m+1)
 17         return sum==0;
 18     if(b[t/xp[x]]==1) return check(x+1,t,sum+1);
 19     else if(b[t/xp[x]]==2) return check(x+1,t,sum-1);
 20     else return check(x+1,t,sum);
 21 }
 22 int main()
 23 {
 24     int nn,mm;
 25     scanf("%d%d",&n,&m);
 26     for(int i=1;i<=n;i++)
 27     {
 28         scanf("%s",bb+1);
 29         for(int j=1;j<=m;j++)
 30         {
 31             if(bb[j]=='.') ma[i][j]=1,nn=i,mm=j;
 32             else if(bb[j]=='-') ma[i][j]=2,nn=i,mm=j;
 33             else if(bb[j]=='|') ma[i][j]=3,nn=i,mm=j;
 34         }
 35     }
 36     xp[0]=1;
 37     for(int i=1;i<=m+1;i++) xp[i]=xp[i-1]*3;
 38     for(int i=0;i<xp[m+1];i++) b[i]=i%3;
 39     for(int i=0;i<xp[m+1];i++)
 40     {
 41         if(check(0,i,0))
 42         {
 43             zz++;
 44             tot[zz]=i;
 45             dl[i]=zz;
 46         }
 47     }
 48     int now=1,la=0;
 49     f[1][1]=1;
 50     for(int i=1;i<=n;i++)
 51     {
 52         for(int j=1;j<=m;j++)
 53         {
 54             la^=1,now^=1;
 55             memset(f[now],0,sizeof(f[now]));
 56             int p,q,x=xp[j-1],y=xp[j],t;
 57             for(int k=1;k<=zz;k++)
 58             {
 59                 p=b[tot[k]/x],q=b[tot[k]/y];
 60                 t=tot[k]-p*x-q*y;
 61                 if(ma[i][j])
 62                 {
 63                     if(!p&&!q)
 64                     {
 65                         if(ma[i][j]==1&&dl[t+x+(y<<1)]) f[now][dl[t+x+(y<<1)]]+=f[la][k];
 66                     }
 67                     else if(!q)
 68                     {
 69                         if(ma[i][j]!=3)
 70                         {
 71                             if(j!=m&&dl[t+(y<<(p-1))]) f[now][dl[t+(y<<(p-1))]]+=f[la][k];
 72                             if(i!=n&&ma[i][j]==1&&dl[t+(x<<(p-1))]) f[now][dl[t+(x<<(p-1))]]+=f[la][k];
 73                         }
 74                     }
 75                     else if(!p)
 76                     {
 77                         if(ma[i][j]!=2)
 78                         {
 79                             if(j!=m&&ma[i][j]==1&&dl[t+(y<<(q-1))]) f[now][dl[t+(y<<(q-1))]]+=f[la][k];
 80                             if(i!=n&&dl[t+(x<<(q-1))]) f[now][dl[t+(x<<(q-1))]]+=f[la][k];
 81                         }
 82                     }
 83                     else if(p==1&&q==2)
 84                     {
 85                         if(!t&&i==nn&&j==mm) ans+=f[la][k];
 86                     }
 87                     else if(p==2&&q==1)
 88                     {
 89                         if(ma[i][j]==1)
 90                         {
 91                             if(dl[t]) f[now][dl[t]]+=f[la][k];
 92                         }
 93                     }
 94                     else if(p==1&&q==1)
 95                     {
 96                         if(ma[i][j]==1)
 97                         {
 98                             int u,tmp;
 99                             for(u=j+1,tmp=0;u<=m&&tmp>=0;tmp+=(b[t/xp[u]]==1)-(b[t/xp[u]]==2),u++);
100                             u--;
101                             if(t-xp[u]<0) continue;
102                             if(dl[t-xp[u]]) f[now][dl[t-xp[u]]]+=f[la][k];
103                         }
104                     }
105                     else if(p==2&&q==2)
106                     {
107                         if(ma[i][j]==1)
108                         {
109                             int u,tmp;
110                             for(u=j-2,tmp=0;u>0&&tmp>=0;tmp+=(b[t/xp[u]]==2)-(b[t/xp[u]]==1),u--);
111                             u++;
112                             if(dl[t+xp[u]]) f[now][dl[t+xp[u]]]+=f[la][k];
113                         }
114                     }
115                 }
116                 else
117                 {
118                     if(!p&&!q&&dl[t]) f[now][dl[t]]+=f[la][k];
119                 }
120             }
121         }
122         for(int j=zz;j>=1;j--)
123         {
124             if(b[tot[j]]==0)
125             {
126                 if(dl[tot[j]/3]) f[now][j]=f[now][dl[tot[j]/3]];
127                 else f[now][j]=0;
128             }
129             else f[now][j]=0;
130         }
131     }
132     printf("%lld\n",ans);
133     return 0;
134 }
View Code

 

转载于:https://www.cnblogs.com/liutianrui/p/8169009.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值