• 插头DP


    先%%学长优秀博客:%%

    并借用他的定义:

    插头DP主要用来处理一系列基于连通性状态压缩的动态规划问题,处理的具体问题有很多种,并且一般数据规模较小。

    由于棋盘有很特殊的结构,使得它可以与“连通性”有很强的联系,因此插头DP最常见的应用要数在棋盘模型上的应用了。

    直接上题

    一、HDU1693 Eat the Trees

    题目大意:给出一张n*m有障碍的棋盘,要求用任意条回路遍历整个棋盘,不能经过障碍格子,要求统计不同的行走方案数。

    Sample Input
    2
    6 3
    1 1 1
    1 0 1
    1 1 1
    1 1 1
    1 0 1
    1 1 1
    2 4
    1 1 1 1
    1 1 1 1
    Sample Output
    Case 1: There are 3 ways to eat the trees.
    Case 2: There are 2 ways to eat the trees.

    具体过程请参考学长博客,我就不搬了(没素质),上解释代码

    重点看Execution函数的分情况讨论的实现 (Execution中判断x==n,y==m的状况可以不写正常转移)

     1 ^:不同则1,相同则0
     2 &:全1则1,有0则0
     3 #include <cstdio>
     4 #include<iostream>
     5 #include <cstring>
     6 using namespace std;
     7 typedef long long LL;
     8 int n,m,bin[20],mp[13][13];
     9 LL f[13][13][(1<<12)+10];//f[i][j][k]表示转移完第i行第j列插头状态为k时的方案数
    10 inline void Execution(int x,int y)
    11 {
    12     int plug1=bin[y-1],plug2=bin[y];//分类bin[y-1]为左插头,bin[y]为上插头
    13     if(x==n&&y==m)//最后状态只走0即可
    14     {
    15         if(mp[x][y])//!障碍且j状态没有插头,^后为有两个插头,及由y-1有两个插头转移
    16             f[x][y][0]+=f[x][y-1][plug1^plug2];
    17         else//障碍并且转移后保证没有插头及一定合法
    18             f[x][y][0]=f[x][y-1][0];//所以没有插头连向它才合法转移
    19         return;
    20     }
    21     for(int j=0;j<bin[m+1];j++)//枚举状态(此时第m+1个插头可以为1)
    22         if(mp[x][y])//!障碍
    23         {
    24             f[x][y][j]+=f[x][y-1][j^plug1^plug2];
    25             //plug1^plug2的第y-1,y这两位为1(从0开始)
    26             //如果j状态有两个插头,^后为没有插头,及由y-1的没有插头转移
    27             //如果j状态没有插头,^后为有两个插头,及由y-1有两个插头转移
    28             //如果j状态有一个,^10变01,及由y-1有一个插头且不转向转移来
    29             //10变10没法实现,只能排除00/11的情况,直接变
    30             if(((j>>(y-1))&1)==((j>>(y))&1)) continue;//都为没插头或都有
    31             f[x][y][j]+=f[x][y-1][j];//10变10,及由y-1有一个插头转向转移
    32         }
    33         else//障碍
    34         {
    35             if(!(j&plug1)&&!(j&plug2))//y-1处理完后该格没有左插头和上插头,同((!((j>>(y-1))&1))&&(!((j>>y)&1)))
    36                 f[x][y][j]=f[x][y-1][j];//及没有插头连向它才合法转移
    37             else f[x][y][j]=0;//否则方案数为0
    38         }
    39 }
    40 int main()
    41 {
    42     int t;
    43     scanf("%d",&t);
    44     bin[0]=1;
    45     for(int i=1;i<=15;i++) //2^最大方案数
    46         bin[i]=bin[i-1]<<1;
    47     //cout<<bin[8]<<endl;
    48     for(int u=1;u<=t;u++)
    49     {
    50         scanf("%d%d",&n,&m);
    51         for(int i=1;i<=n;i++)
    52             for(int j=1;j<=m;j++)
    53                 scanf("%d",&mp[i][j]);
    54         memset(f,0,sizeof(f));
    55         f[1][0][0]=1;//*************初始化第0格*****************//
    56         for(int i=1;i<=n;i++)
    57         {
    58             for(int j=1;j<=m;j++) Execution(i,j);//逐格递推
    59             if(i!=n)//行间转移:当前行的0到m-1转移到下一行的1到m
    60                 for(int j=0;j<bin[m];j++)//bin[m]及第m个插头不可能为1
    61                     f[i+1][0][j<<1]=f[i][m][j];//初始化第0格
    62         }
    63         printf("Case %d: There are %lld ways to eat the trees.\n",u,f[n][m][0]);//最后状态不能再有插头
    64     }
    65 }

     注意点:(自己的zz错误)

    (1)行间转移没判 i!=n        59行

    (2)插头从0到m,第m个插头不能为1,写成bin[m+1]         60行

    (3)行间转移j<<1写成j>>1,左移1后i+1行的第0位为0         61行

    (4)判断都有或没有插头跳过时没&1            30行

  • 相关阅读:
    Delphi利用Windows GDI实现文字倾斜
    再学 GDI+文本输出文本样式
    GDI+在Delphi程序的应用 Photoshop色相饱和度明度功能
    GDI+图像与GDI位图的相互转换
    走进JavaWeb技术世界12:从手动编译打包到项目构建工具Maven
    走进JavaWeb技术世界11:单元测试框架Junit
    走进JavaWeb技术世界10:从JavaBean讲到Spring
    走进JavaWeb技术世界9:Java日志系统的诞生与发展
    走进JavaWeb技术世界8:浅析Tomcat9请求处理流程与启动部署过程
    随笔总和
  • 原文地址:https://www.cnblogs.com/qwertyuiopasdfghjklzxcvbnm/p/11260734.html
Copyright © 2020-2023  润新知