zoukankan      html  css  js  c++  java
  • 【插头DP】BZOJ3125-city

    开学忙成狗,刷题慢如蜗牛……

    【题目大意】

    给出一个m*n的矩阵里面有一些格子为障碍物,一些格子只能上下通行,一些格子只能左右通行,一些格子上下左右都能通行。问经过所有非障碍格子的哈密顿回路个数。

    【思路】

    和BZOJ1814差不多,增加几个比较简单的判断即可。详见代码。

    【错误点】

    一开始我把三种可通行的情况写在一起,有点混乱了……拆开成3个函数就好啦!

    下次注意程序的可读性。

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 #include<vector>
      6 using namespace std;
      7 typedef long long ll;
      8 const int MAXN=14;
      9 const int HASH=30007;
     10 int ex,ey;
     11 int m,n;
     12 int maze[MAXN][MAXN];
     13 int code[MAXN],ch[MAXN];
     14 struct HashMap
     15 {
     16     vector<int> hash[HASH];//存储f和state的下标 
     17     vector<ll> f,state;//存储对应的方案数和状态 
     18     void init()
     19     {
     20         for (int i=0;i<HASH;i++) vector<int>().swap(hash[i]);
     21         vector<ll>().swap(f);
     22         vector<ll>().swap(state);
     23     }
     24     void push(ll st,ll ans)
     25     {
     26         int h=st%HASH;
     27         for (int i=0;i<hash[h].size();i++)
     28         {
     29             int now=hash[h][i];
     30             if (state[now]==st)//如果已经存储了当前状态,直接累加 
     31             {
     32                 f[now]+=ans;
     33                 return;
     34             }
     35         }
     36         //如果没有存储过当前状态,累加 
     37         state.push_back(st);
     38         f.push_back(ans);
     39         hash[h].push_back(state.size()-1);
     40     }
     41 }dp[2];
     42 
     43 void decode(ll st)
     44 {
     45     memset(code,0,sizeof(code));
     46     for (int i=n;i>=0;i--)
     47     {
     48         code[i]=st&7;//每三位代表一个信息 
     49         st>>=3;
     50     }
     51 }
     52 
     53 ll encode()
     54 //用最小表示法重新编码 
     55 {
     56     int cnt=1;
     57     memset(ch,-1,sizeof(ch));
     58     ch[0]=0;
     59     long long st=0;
     60     for (int i=0;i<=n;i++)
     61     {
     62         if (ch[code[i]]==-1) ch[code[i]]=cnt++;
     63         code[i]=ch[code[i]];
     64         st<<=3;
     65         st|=code[i]; 
     66     } 
     67     return st;
     68 }
     69 
     70 void shift()
     71 {
     72     for (int i=n;i>0;i--) code[i]=code[i-1];
     73     code[0]=0;
     74 }
     75 
     76 
     77 void dpblank(int i,int j,int cur)
     78 {
     79     for (int k=0;k<dp[1-cur].state.size();k++)
     80     {
     81         decode(dp[1-cur].state[k]);
     82         int left=code[j-1];//左插头 
     83         int up=code[j];//上插头
     84         
     85         /*如果上下插头都没有*/ 
     86         if (!left && !up)
     87         {
     88             if (maze[i][j+1] && maze[i+1][j])
     89             {
     90                 code[j-1]=code[j]=MAXN-1;
     91                 //这里只要随便设置一个大数即可
     92                 
     93                 //【attention】这里千万不可以设置成MAXN,否则ch数组会抱★★★★★★★★
     94                 
     95                 //因为encode会重新用最小表示法编码 
     96                 dp[cur].push(encode(),dp[1-cur].f[k]);
     97             }
     98         }
     99         
    100         /*只有上插头或者只有左插头*/
    101         if ((left&&(!up))||((!left)&&up))
    102         {
    103             
    104             int t=left|up;
    105             if (maze[i][j+1])//右边没有障碍
    106             {
    107                 code[j-1]=0;
    108                 code[j]=t;
    109                 dp[cur].push(encode(),dp[1-cur].f[k]);
    110             } 
    111             if (maze[i+1][j])//下面没有障碍
    112             {
    113                 code[j-1]=t;
    114                 code[j]=0;
    115                 if (j==n) shift();
    116                 dp[cur].push(encode(),dp[1-cur].f[k]);
    117             }
    118         }
    119         
    120         /*上插头和右插头都有*/
    121         if (left && up)
    122         {
    123             if (left==up)
    124             {
    125                 if (i==ex && j==ey)
    126                 {
    127                     code[j-1]=code[j]=0;
    128                     if (j==n) shift();
    129                     dp[cur].push(encode(),dp[1-cur].f[k]);
    130                 }
    131             }
    132             else
    133             {
    134                 code[j-1]=code[j]=0;
    135                 for (int t=0;t<=n;t++)
    136                     if (code[t]==up) code[t]=left;
    137                 if (j==n) shift();
    138                 dp[cur].push(encode(),dp[1-cur].f[k]);
    139             }
    140         } 
    141     }
    142 }
    143 
    144 void DpHorizon(int cur,int i,int j)//只能水平走 
    145 {
    146     for (int k=0;k<dp[1-cur].state.size();k++)
    147     {
    148         decode(dp[1-cur].state[k]);
    149         int left=code[j-1],up=code[j];
    150         
    151         if(!up && left&& maze[i][j+1]!=0 && maze[i][j+1]!=3&& j!=n&&j!=1) //右边不是障碍物,也能够水平走,并且不是最右边 
    152         {
    153             code[j-1]=0;
    154             code[j]=left;
    155             dp[cur].push(encode(),dp[1-cur].f[k]);
    156         }     
    157     } 
    158     
    159 }
    160 
    161 void DpVertical(int cur,int i,int j)//只能竖直走 
    162 {
    163     for (int k=0;k<dp[1-cur].state.size();k++)
    164     {
    165         decode(dp[1-cur].state[k]);
    166         int left=code[j-1],up=code[j];
    167         
    168         if(up && !left && maze[i+1][j]!=0 && maze[i+1][j]!=2&&i!=m&&i!=1)//下边不是障碍物,也能够竖直走 
    169         {
    170             code[j-1]=up;
    171             code[j]=0;
    172             if(j==n)shift();
    173             dp[cur].push(encode(),dp[1-cur].f[k]);
    174         }     
    175     } 
    176     
    177 }
    178 
    179 void dpblock(int i,int j,int cur)
    180 {
    181     int k=0;
    182     for (int k=0;k<dp[1-cur].state.size();k++)
    183     {
    184         decode(dp[1-cur].state[k]);
    185         code[j-1]=code[j]=0;
    186         if (j==n) shift();
    187         dp[cur].push(encode(),dp[1-cur].f[k]);
    188     }
    189 }
    190 
    191 void solve()
    192 {
    193     int cur=0;
    194     ll ans=0;
    195     dp[cur].init();
    196     dp[cur].push(0,1);//DP数组初始化 
    197     for (int i=1;i<=m;i++)
    198         for (int j=1;j<=n;j++)
    199         {
    200             cur^=1;
    201             dp[cur].init();
    202             if (maze[i][j]==1) dpblank(i,j,cur);
    203                 else if (maze[i][j]==0)  dpblock(i,j,cur);
    204                 else if  (maze[i][j]==2)DpHorizon(cur,i,j);
    205                 else  DpVertical(cur,i,j);
    206         }
    207     for (int i=0;i<dp[cur].state.size();i++)
    208         ans+=dp[cur].f[i];
    209     printf("%lld",ans);
    210 }
    211 
    212 
    213 void init()
    214 {
    215     scanf("%d%d",&m,&n);
    216     for (int i=1;i<=m;i++)
    217     {
    218         char str[MAXN];
    219         scanf("%s",str);
    220         for (int j=1;j<=n;j++)
    221         {
    222             if (str[j-1]=='#') maze[i][j]=0;
    223             if (str[j-1]=='.') maze[i][j]=1;
    224             if (str[j-1]=='-') maze[i][j]=2;
    225             if (str[j-1]=='|') maze[i][j]=3;
    226             if (str[j-1]!='#') ex=i,ey=j;
    227         }
    228     }
    229 }
    230 
    231 int main()
    232 {
    233 
    234     init();
    235     if (ex==0) puts("0");//如果没有一个是空格的话直接输出0 
    236         else solve();
    237    
    238 }
  • 相关阅读:
    [转]给明年依然年轻的我们:欲望、外界、标签、天才、时间、人生目标、现实、后悔、和经历
    C#后台发送HTTP请求
    asp.net 用户控件
    P1414 又是毕业季II
    P2254 [NOI2005]瑰丽华尔兹
    P1081 开车旅行
    P1084 疫情控制
    P1852 [国家集训队]跳跳棋
    P1074 靶形数独
    平时二十三测
  • 原文地址:https://www.cnblogs.com/iiyiyi/p/5870024.html
Copyright © 2011-2022 走看看