zoukankan      html  css  js  c++  java
  • HDU 1693 Eat the Trees(插头DP、棋盘哈密顿回路数)+ URAL 1519 Formula 1(插头DP、棋盘哈密顿单回路数)

    插头DP基础题的样子。。。输入N,M<=11,以及N*M的01矩阵,0(1)表示有(无)障碍物。输出哈密顿回路(可以多回路)方案数。。。

     

    看了个ppt,画了下图。。。感觉还是挺有效的。。。

    参考http://www.cnblogs.com/kuangbin/archive/2012/10/02/2710343.html

    以及推荐cd琦的论文ppthttp://wenku.baidu.com/view/4fe4ac659b6648d7c1c74633.html

    向中学生学习~~

    感觉以后可能还会要看这篇日志。所以特意加了较多的注释。。。观客可以看注释=。=推荐画示意图。。。。

    复杂度O(n*m*2^(m+1))

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <iostream>
     4 #include <algorithm>
     5 #include <cmath>
     6 #include <string>
     7 #include <vector>
     8 #include <queue>
     9 #include <set>
    10 using namespace std;
    11 
    12 #define ll long long
    13 #define inf 0x3f3f3f3f
    14 #define eps 1e-8
    15 
    16 int a[12][12];
    17 ll dp[12][12][1<<12];
    18 int main(){
    19     int t,ca=0;
    20     scanf("%d",&t);
    21     while(t--){
    22         int n,m;
    23         scanf("%d%d",&n,&m);
    24         for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)scanf("%d",&a[i][j]);
    25         memset(dp,0,sizeof(dp));
    26         dp[1][0][0]=1;
    27         int ma=(1<<(m+1));
    28         for(int i=1;i<=n;++i){
    29             for(int j=1;j<=m;++j){
    30                 for(int k=0;k<ma;++k){
    31                     int d=1<<(j-1),r=1<<j;
    32                     if(a[i][j]){// 该位置无障碍
    33                         if( ( (k&d)&&(k&r) ) || ( (~k&d)&&(~k&r)) )// 右插下插同时有或同时无,必须翻转
    34                             dp[i][j][k]=dp[i][j-1][k^d^r];
    35                         else // 右插下插只有一个,可翻转可不翻转
    36                             dp[i][j][k]=dp[i][j-1][k]+dp[i][j-1][k^d^r];
    37                     }
    38                     else {// 该位置有障碍
    39                         if((k&d)==0&&(k&r)==0)// 没有右插没有下插,则方案数跟随
    40                             dp[i][j][k]=dp[i][j-1][k];
    41                     }
    42                 }
    43             }
    44             if(i+1<=11)
    45             for(int k=0;k<(1<<m);++k)// 换行去掉上一行的右插,下一行的开头没有进来的左插,请画图
    46                 dp[i+1][0][k<<1]=dp[i][m][k];
    47         }
    48         printf("Case %d: There are %I64d ways to eat the trees.
    ",++ca,dp[n][m][0]);
    49     }
    50     return 0;
    51 }
    View Code

    做了上面那个入门级别的插头DP。。。做了个还是入门级别的。。。。

    输入N,M<=12,以及N*M的01矩阵,'*'('.')表示有(无)障碍物。输出哈密顿单回路方案数。。。

    这一题需要用到括号匹配,最小表示法(上面那题可以不用,我的代码就是没有用到的)。。。

    这一题参考了别人的代码,尝试了2种表示方法,一种是直接存括号对应的连通分量标号,一种是只存括号的类型。。。

    我的第一种方法300+ms,第二种100+ms。。。感觉还是有点区别的。。。因为存连通分量标号需要用到3位(连通分量标号最大值为MAXM/2),而括号类型只需要2位

    。。

    而这题跟上一题的区别,就是,单哈密顿回路的括号匹配,如果左插是'(',下插是')',那只能在最后一个非障碍物的位置连接。。。。

    具体看代码吧。。。还是建议画下示意图。。。

    还有一点就是,由于用到HASH,所以HASH太大太小都可能会TLE

    300+ms的版本(其实就是那个链接里的。。。。):

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <iostream>
      4 #include <algorithm>
      5 #include <cmath>
      6 #include <string>
      7 #include <vector>
      8 #include <queue>
      9 #include <set>
     10 using namespace std;
     11 
     12 #define ll long long
     13 #define inf 0x3f3f3f3f
     14 #define eps 1e-8
     15 
     16 #define maxd 15
     17 #define HASH 100007
     18 #define STATE 1000010
     19 
     20 int n,m;
     21 int maze[maxd][maxd],code[maxd];
     22 int ch[maxd];//最小表示法使用
     23 int ex,ey;//最后一个非障碍格子的坐标
     24 struct HASHMAP{
     25     int head[HASH],nxt[STATE],sz;
     26     ll state[STATE];
     27     ll f[STATE];
     28     void clear(){sz=0;memset(head,-1,sizeof(head));}
     29     void push(ll st,ll ans){
     30         int h=st%HASH;
     31         for(int i=head[h];i!=-1;i=nxt[i])
     32             if(state[i]==st){
     33                 f[i]+=ans;
     34                 return;
     35             }
     36         state[sz]=st;
     37         f[sz]=ans;
     38         nxt[sz]=head[h];
     39         head[h]=sz++;
     40     }
     41 }hm[2];
     42 void decode(int *code,int m,ll    st){
     43     for(int i=m;i>=0;i--)code[i]=st&7,st>>=3;
     44 }
     45 ll encode(int *code,int m){//最小表示法
     46     int cnt=1;
     47     memset(ch,-1,sizeof(ch));
     48     ch[0]=0;
     49     ll st=0;
     50     for(int i=0;i<=m;i++){
     51         if(ch[code[i]]==-1)ch[code[i]]=cnt++;
     52         code[i]=ch[code[i]];
     53         st<<=3;
     54         st|=code[i];
     55     }
     56     return st;
     57 }
     58 void shift(int *code,int m){
     59     for(int i=m;i>0;i--)code[i]=code[i-1];
     60     code[0]=0;
     61 }
     62 void dpblank(int i,int j,int cur){
     63     for(int k=0;k<hm[cur].sz;k++){
     64         decode(code,m,hm[cur].state[k]);
     65         int left=code[j-1],up=code[j];
     66         if(left&&up){
     67             if(left==up){//只能出现在最后一个非障碍格子
     68                 if(i==ex&&j==ey){
     69                     code[j-1]=code[j]=0;
     70                     if(j==m)shift(code,m);
     71                     hm[cur^1].push(encode(code,m),hm[cur].f[k]);
     72                 }
     73             }
     74             else{//不在同一个连通分量则合并
     75                 code[j-1]=code[j]=0;
     76                 for(int t=0;t<=m;t++)
     77                     if(code[t]==up)code[t]=left;
     78                 if(j==m)shift(code,m);
     79                 hm[cur^1].push(encode(code,m),hm[cur].f[k]);
     80             }
     81         }
     82         else if(left || up){
     83             int t = left + up;
     84             if(maze[i][j+1]){
     85                 code[j-1]=0;
     86                 code[j]=t;
     87                 hm[cur^1].push(encode(code,m),hm[cur].f[k]);
     88             }
     89             if(maze[i+1][j]){
     90                 code[j-1]=t;
     91                 code[j]=0;
     92                 if(j==m)shift(code,m);
     93                 hm[cur^1].push(encode(code,m),hm[cur].f[k]);
     94             }
     95         }
     96         else{//无插头,则构造新的连通块
     97             if(maze[i][j+1]&&maze[i+1][j]){
     98                 code[j-1]=code[j]=13;
     99                 hm[cur^1].push(encode(code,m),hm[cur].f[k]);
    100             }
    101         }
    102     }
    103 }
    104 void dpblock(int i,int j,int cur){
    105     for(int k=0;k<hm[cur].sz;k++){
    106         decode(code,m,hm[cur].state[k]);
    107         code[j-1]=code[j]=0;
    108         if(j==m)shift(code,m);
    109         hm[cur^1].push(encode(code,m),hm[cur].f[k]);
    110     }
    111 }
    112 char str[maxd];
    113 void init(){
    114     memset(maze,0,sizeof(maze));
    115     ex=0;
    116     for(int i=1;i<=n;i++){
    117         scanf("%s",str+1);
    118         for(int j=1;j<=m;j++){
    119             if(str[j]=='.'){// 无障碍
    120                 ex=i,ey=j;
    121                 maze[i][j]=1;
    122             }
    123         }
    124     }
    125 }
    126 void solve(){
    127     int cur=0;
    128     ll ans=0;
    129     hm[0].clear();
    130     hm[0].push(0,1);
    131     for(int i=1;i<=n;i++)
    132         for(int j=1;j<=m;j++){
    133             hm[cur^1].clear();
    134             if(maze[i][j])dpblank(i,j,cur);
    135             else dpblock(i,j,cur);
    136             cur^=1;
    137         }
    138     for(int i=0;i<hm[cur].sz;i++)
    139         ans+=hm[cur].f[i];
    140     printf("%I64d
    ",ans);
    141 }
    142 int main(){
    143     while(~scanf("%d%d",&n,&m)){
    144         init();
    145         if(ex==0)puts("0");// 没有空的格子
    146         else solve();
    147     }
    148     return 0;
    149 }
    View Code

    100+ms的版本(改编自那个链接里的。。。。):

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <iostream>
      4 #include <algorithm>
      5 #include <cmath>
      6 #include <string>
      7 #include <vector>
      8 #include <queue>
      9 #include <set>
     10 using namespace std;
     11 
     12 #define ll long long
     13 #define inf 0x3f3f3f3f
     14 #define eps 1e-8
     15 
     16 #define maxd 15
     17 #define HASH 100007
     18 #define STATE 1000010
     19 
     20 int n,m;
     21 int maze[maxd][maxd],code[maxd];
     22 int ch[maxd];//最小表示法使用
     23 int ex,ey;//最后一个非障碍格子的坐标
     24 struct HASHMAP{
     25     int head[HASH],nxt[STATE],sz;
     26     ll state[STATE];
     27     ll f[STATE];
     28     void clear(){sz=0;memset(head,-1,sizeof(head));}
     29     void push(ll st,ll ans){
     30         int h=st%HASH;
     31         for(int i=head[h];i!=-1;i=nxt[i])
     32             if(state[i]==st){
     33                 f[i]+=ans;
     34                 return;
     35             }
     36         state[sz]=st;
     37         f[sz]=ans;
     38         nxt[sz]=head[h];
     39         head[h]=sz++;
     40     }
     41 }hm[2];
     42 void decode(int *code,int m,ll    st){
     43     for(int i=0;i<=m;++i)code[i]=st&3,st>>=2;
     44 }
     45 ll encode(int *code,int m){//最小表示法
     46     ll st=0;
     47     for(int i=m;i>=0;--i)
     48         st=st<<2|code[i];
     49     return st;
     50 }
     51 void shift(int *code,int m){
     52     for(int i=m;i>0;i--)code[i]=code[i-1];
     53     code[0]=0;
     54 }
     55 void dpblank(int i,int j,int cur){
     56     for(int k=0;k<hm[cur].sz;k++){
     57         decode(code,m,hm[cur].state[k]);
     58         int left = code[j-1],up = code[j];
     59         if(left&&up){
     60             if(left==2 && up==1){// 只能出现在最后一个非障碍格子
     61                 if(i==ex&&j==ey){
     62                     code[j-1]=code[j]=0;
     63                     ll tmp = encode(code,m);
     64                     if(j==m)tmp<<=2;
     65                     hm[cur^1].push(tmp,hm[cur].f[k]);
     66                 }
     67             }
     68             else{//不在同一个连通分量则合并
     69                 if(left==1 && up==1){//  ...(...(...))... ==> ...(...)...##...
     70                     for(int jj=j-1,cnt=0;jj>=0;--jj){
     71                         if(code[jj]==1)++cnt;
     72                         else if(code[jj]==2)--cnt;
     73                         if(cnt==0){code[jj]=3-code[jj];break;}
     74                     }
     75                     code[j-1]=code[j]=0;
     76                 }
     77                 else if(left==2 && up==2){//  ...((...)...)... ==> ...##...(...)...
     78                     for(int jj=j,cnt=0;jj<=m;++jj){
     79                         if(code[jj]==1)++cnt;
     80                         else if(code[jj]==2)--cnt;
     81                         if(cnt==0){code[jj]=3-code[jj];break;}
     82                     }
     83                     code[j-1]=code[j]=0;
     84                 }
     85                 else if(left==1 && up==2){// ...(...)(...)... ==> ...(...##...)...
     86                     code[j-1]=code[j]=0;
     87                 }
     88                 if(j==m)shift(code,m);
     89                 hm[cur^1].push(encode(code,m),hm[cur].f[k]);
     90             }
     91         }
     92         else if(left || up){
     93             int t = left | up;
     94             if(maze[i][j+1]){
     95                 code[j-1]=0;
     96                 code[j]=t;
     97                 hm[cur^1].push(encode(code,m),hm[cur].f[k]);
     98             }
     99             if(maze[i+1][j]){
    100                 code[j-1]=t;
    101                 code[j]=0;
    102                 if(j==m)shift(code,m);
    103                 hm[cur^1].push(encode(code,m),hm[cur].f[k]);
    104             }
    105         }
    106         else{//无插头,则构造新的连通块
    107             if(maze[i][j+1]&&maze[i+1][j]){
    108                 code[j-1]=2,code[j]=1;
    109                 hm[cur^1].push(encode(code,m),hm[cur].f[k]);
    110             }
    111         }
    112     }
    113 }
    114 void dpblock(int i,int j,int cur){
    115     for(int k=0;k<hm[cur].sz;k++){
    116         decode(code,m,hm[cur].state[k]);
    117         code[j-1]=code[j]=0;
    118         if(j==m)shift(code,m);
    119         hm[cur^1].push(encode(code,m),hm[cur].f[k]);
    120     }
    121 }
    122 char str[maxd];
    123 void init(){
    124     memset(maze,0,sizeof(maze));
    125     ex=0;
    126     for(int i=1;i<=n;i++){
    127         scanf("%s",str+1);
    128         for(int j=1;j<=m;j++){
    129             if(str[j]=='.'){// 无障碍
    130                 ex=i,ey=j;
    131                 maze[i][j]=1;
    132             }
    133         }
    134     }
    135 }
    136 void solve(){
    137     int cur=0;
    138     ll ans=0;
    139     hm[0].clear();
    140     hm[0].push(0,1);
    141     for(int i=1;i<=n;i++)
    142         for(int j=1;j<=m;j++){
    143             hm[cur^1].clear();
    144             if(maze[i][j])dpblank(i,j,cur);
    145             else dpblock(i,j,cur);
    146             cur^=1;
    147         }
    148     for(int i=0;i<hm[cur].sz;i++)
    149         ans+=hm[cur].f[i];
    150     printf("%I64d
    ",ans);
    151 }
    152 int main(){
    153     while(~scanf("%d%d",&n,&m)){
    154         init();
    155         if(ex==0)puts("0");// 没有空的格子
    156         else solve();
    157     }
    158     return 0;
    159 }
    View Code
  • 相关阅读:
    Oracle分页查询
    Oracle表空间
    Oracle中DBA常用操作
    数据库的约束
    数据库设计的三范式
    数据类型的比较 有四种情况
    github快速上手
    3D正方体做法
    animation-声明关键帧
    轮播图样式
  • 原文地址:https://www.cnblogs.com/nextbin/p/3707473.html
Copyright © 2011-2022 走看看