• 插头DP代码


      1 #include<cstdio>
      2 #include<cstring>
      3 #include<iostream>
      4 using namespace std;
      5 const int cube=(int)1e9;
      6 const int mod=2601;
      7 int n,m;
      8 struct Data_Analysis//有关高精
      9 {
     10     int bit[6];//存储答案的高精数组,bit[i]中不止一个数,会存在一个很大的数
     11     inline void Clear()  {memset(bit,0,sizeof(bit));}
     12     Data_Analysis()  {Clear();}//初始化清空
     13     inline void Set(int t)
     14     {
     15         Clear();
     16         while(t)  {bit[++bit[0]]=t%cube;  t/=cube;}//类似于高精中的对10取模及做乘法,只不过变为对1e9取模做乘法
     17     }
     18     inline int &operator [](int x)  {return bit[x];}
     19     inline void Print()
     20     {
     21         printf("%d",bit[bit[0]]);//bit[0]可能小于0,但是此时也需要输出0,所以需要这么一步
     22         for(int i=bit[0]-1;i>0;i--)  printf("%d",bit[i]);//正常倒着输出
     23         printf("
    ");
     24     }
     25     inline Data_Analysis operator + (Data_Analysis b)//高精加
     26     {
     27         Data_Analysis c;  c.Clear();  c[0]=max(bit[0],b[0])+1;//两数相加的位数最多为位数大的那个+1
     28         for(int i=1;i<=c[0];i++)  {c[i]+=bit[i]+b[i];  c[i+1]+=c[i]/cube;  c[i]%=cube;}
     29         while(!c[c[0]])  c[0]--;//排除最高位的0
     30         return c;
     31     }
     32     inline void operator += (Data_Analysis b)  {*this=*this+b;}//*this"返回当前对象的引用 或者说返回该对象本身 还是当前对象的克隆"
     33     inline void operator = (int x)  {Set(x);}//最初bit[0]=0,计数用,所以在最初赋值时也直接用set,把bit[0]留出来
     34 }Ans;
     35 struct Hash_Sheet//有关hash
     36 {
     37     Data_Analysis val[mod];//方案数
     38     int key[mod],size,hash[mod];//所表示的真实状态,元素个数,是hash表中第几个元素
     39     inline void Initialize()//初始化清空
     40     {
     41         size=0;  memset(val,0,sizeof(val));
     42         memset(key,-1,sizeof(key));  memset(hash,0,sizeof(hash));
     43     }
     44     inline void Newhash(int id,int v)  {hash[id]=++size;  key[size]=v;}//在hash表中添加新元素
     45     Data_Analysis &operator [](const int State)
     46     {
     47         for(int i=State%mod;;i=(i+1==mod)?0:i+1)//不停的通过+1的操作向后找,循环查找,直到找到,通过retrun结束for循环
     48         {
     49             if(!hash[i])  Newhash(i,State);//没有就添加新元素
     50             if(key[hash[i]]==State)  return val[hash[i]];//找到该状态,返回该状态下的方案数
     51         }
     52     }
     53 }f[2];
     54 //所有状态均为4进制(以2进制为基础,每两位看作一个整体代表4进制,利用位运算简化操作过程)
     55 //0无插头 1左插头 2右插头
     56 inline int Find(int State,int id)//查找该处插头种类,id代表所在格子是第几列,所以id=x时对应二进制表示中(两位一整体)第x-1个整体
     57 {
     58     return (State>>((id-1)<<1))&3;//(id-1)<<1即(id-1)*2,目的是把需要被查找的位置移到第0,1位处,&3会把除最后两位之外的其他位均置0,并且不改变最后两位
     59 }
     60 inline void Set(int &State,int bit,int val)//修改插头类型
     61 {
     62     bit=(bit-1)<<1;//由于两位一整体,直接算出当前整体的前一位在哪
     63     State|=3<<bit;//先置1
     64     State^=3<<bit;//后置0
     65     State|=val<<bit;//把当前位置改变为val
     66 }
     67 inline int Link(int State,int pos)//查找对应的另一个插头在哪
     68 {
     69     int cnt=0;//标记已经历过的左右插头能否相互抵消,当相互抵消时证明找到了当前插头的对应插头
     70     int Delta=(Find(State,pos)==1)?1:-1;//当前是左插头,就向右找,否则向左找
     71     for(int i=pos;i&&i<=m+1;i+=Delta)//有可能向左,有可能向右,所以要保证1<=i<=m+1(插头编号由1到m+1)
     72     {
     73         int plug=Find(State,i);
     74         if(plug==1)  cnt++;
     75         else if(plug==2)  cnt--;
     76         if(cnt==0)  return i;//一一对应证明找到了相对的左/右插头
     77     }
     78     return -1;//扫了一遍没找到
     79 }
     80 inline void Execution(int x,int y)
     81 {
     82     //((x-1)*m+y)求出是第几个格
     83     int now=((x-1)*m+y)&1;//now只有可能=0/1,只保留最后一位
     84     int last=now^1;//0^1=1 1^1=0记录连着的上一个格子,类似于滚动数组只用0/1
     85     int tot=f[last].size;//上一个格子共有tot种不同状态
     86     f[now].Initialize();//给当前格子清零
     87     for(int i=1;i<=tot;i++)
     88     {
     89         int State=f[last].key[i];//枚举决策上一个格子时的所有不同状态
     90         Data_Analysis Val=f[last].val[i];//状态所对应的方案数
     91         int plug1=Find(State,y),plug2=Find(State,y+1);//寻找当前决策的格子上的两个插头的种类
     92         if(Link(State,y)==-1||Link(State,y+1)==-1)  continue;//没有对应的插头
     93         if(!plug1&&!plug2)//没有插头
     94         {
     95             if(x!=n&&y!=m)  {Set(State,y,1);  Set(State,y+1,2);  f[now][State]+=Val;}//只要不是最后一个格子,就建下插头及右插头,作为1插头和2插头
     96         }
     97         else if(plug1&&!plug2)//只有一个来自左边的插头
     98         {
     99             if(x!=n)  f[now][State]+=Val;//转弯,连接一个下插头
    100             if(y!=m)  {Set(State,y,0);  Set(State,y+1,plug1);  f[now][State]+=Val;}//直走,向右
    101         }
    102         else if(!plug1&&plug2)//只有一个来自上面的插头
    103         {
    104             if(y!=m)  f[now][State]+=Val;//转弯,连接一个右插头
    105             if(x!=n)  {Set(State,y,plug2);  Set(State,y+1,0);  f[now][State]+=Val;}//直走,向下
    106         }
    107         else if(plug1==1&&plug2==1)//两个左插头,把靠里的那个左插头的右插头变为左插头,两个插头联通,置为没有
    108             {Set(State,Link(State,y+1),1);  Set(State,y,0);  Set(State,y+1,0);  f[now][State]+=Val;}
    109         else if(plug1==1&&plug2==2)//左边是左插头,右边是右插头
    110             {if(x==n&&y==m)  Ans+=Val;}//如果是最后一个格子,直接封口
    111         else if(plug1==2&&plug2==1)//左边是右插头,右边是左插头,没影响,直接判联通,置为0,对对应插头无影响
    112             {Set(State,y,0);  Set(State,y+1,0);  f[now][State]+=Val;}
    113         else if(plug1==2&&plug2==2)//两个右插头,联通置为0,靠里的左插头变右
    114             {Set(State,Link(State,y),2);  Set(State,y,0);  Set(State,y+1,0);  f[now][State]+=Val;}
    115     }
    116 }
    117 int main()
    118 {
    119     scanf("%d%d",&n,&m);
    120     if(m>n)  swap(n,m);//用较小数状压
    121     f[0].Initialize();  f[0][0]=1;
    122     for(int i=1;i<=n;i++)
    123     {
    124         for(int j=1;j<=m;j++)  Execution(i,j);
    125         if(i!=n)//行间转移
    126         {
    127             int now=(i*m)&1,tot=f[now].size;
    128             for(int j=1;j<=tot;j++)  f[now].key[j]<<=2;//两个一整体
    129         }
    130     }
    131     Ans+=Ans;  Ans.Print();
    132 }
    View Code
  • 相关阅读:
    关于自学的又一点思考
    hdu 1176 免费馅饼
    AS400 Sequel View报表学习笔记 (一)
    AS400 QUERY中的Unmatched records探讨。
    AS400 SDA development Note (1)
    关于Actionscript 3.0中KeyboardEvent的调试需注意的问题
    iPhone开发的常用的API函数库
    Cocos2DiPhone编程中按钮的设置(MenueItem类系的介绍)
    维基网上公布的世界上的一些算法<希望能对寻找算法的一些朋友有帮助>
    关于面向对象编程与面向过程编程的介绍与解释
  • 原文地址:https://www.cnblogs.com/hzjuruo/p/11276692.html
Copyright © 2020-2023  润新知