插头dp总结

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<vector>
  5 #define mod 192617
  6 #define ll long long
  7 using namespace std;
  8 int n,m;
  9 int now,to;//滚动
 10 int hs[2][mod<<3];//hash
 11 ll wei[2][mod<<3];//
 12 int ne[2][mod<<3];//
 13 int he[2][mod];//(前向星)
 14 ll alans=0;
 15 vector<int>sta[2];//储存状态
 16 char s[17];
 17 void addstate(int state,ll val)//添加新状态
 18 {
 19     int k=state%mod;
 20     for(int i=he[to][k];i;i=ne[to][i])
 21     {
 22         if(hs[to][i]==state)
 23         {
 24             wei[to][i]+=val;
 25             return;
 26         }
 27     }
 28     sta[to].push_back(state);
 29     int t=sta[to].size();
 30     ne[to][t]=he[to][k];
 31     wei[to][t]=val;
 32     hs[to][t]=state;
 33     he[to][k]=t;
 34         
 35 }
 36 ll getval(int state)//查询某状态下权值
 37 {
 38     int k=state%mod;
 39     for(int i=he[now][k];i;i=ne[now][i])
 40         if(hs[now][i]==state)
 41             return wei[now][i];    
 42 }
 43 int get(int state,int l)//查询某状态下的某位置的插头类型
 44 {
 45     return (state>>(l<<1))&3;
 46 }
 47 int renew(int state,int l,int ss)//更新状态/插头类型
 48 {
 49     state|=3<<(l<<1);
 50     state^=3<<(l<<1);
 51     state|=ss<<(l<<1);
 52     return state;
 53 }
 54 int fr1to2(int state,int fr)//两个1插头撞到,找2插头
 55 {
 56     int p=0,k;
 57     for(int i=fr;i<=m+1;++i)
 58     {
 59         k=get(state,i);
 60         if(k==1)++p;
 61         if(k==2)--p;
 62         if(!p)return i;
 63     }
 64 }
 65 int fr2to1(int state,int fr)//两个2插头撞到,找1插头
 66 {
 67     int p=0,k;
 68     for(int i=fr;i;--i)
 69     {
 70         k=get(state,i);
 71         if(k==1)++p;
 72         if(k==2)--p;
 73         if(!p)return i;
 74     }
 75 }
 76 void pr(int state)//调试输出
 77 {
 78     for(int i=1;i<=m+1;++i)
 79     {
 80         printf("%d",get(state,i));
 81     }
 82     printf(" %lld\n",getval(state));
 83 }
 84 void work(int h,int l)
 85 {
 86     int state,pl,pu;
 87     ll val,ans=0;
 88     now^=1;to^=1;
 89     printf("%d %d\n",h,l);
 90     memset(he[to],0,sizeof(he[to]));sta[to].clear();
 91     switch(s[l])
 92     {
 93         case '.':{
 94             for(int i=0;i<sta[now].size();++i)
 95             {
 96                 state=sta[now][i];
 97                 val=getval(state);
 98                 pl=get(state,l);
 99                 pu=get(state,l+1);
100                 pr(state);
101                 if(!pl&&!pu)//又臭又长的分类讨论
102                 {
103                     state=renew(state,l,1);
104                     state=renew(state,l+1,2);
105                     addstate(state,val);
106                 }
107                 else if(!pl&&pu)
108                 {
109                     addstate(state,val);
110                     state=renew(state,l,pu);
111                     state=renew(state,l+1,0);
112                     addstate(state,val);
113                 }
114                 else if(pl&&!pu)
115                 {
116                     addstate(state,val);
117                     state=renew(state,l+1,pl);
118                     state=renew(state,l,0);
119                     addstate(state,val);
120                 }
121                 else if(pl==1&&pu==2)
122                 {
123                     state=renew(state,l+1,0);
124                     state=renew(state,l,0);
125                     if(!state)ans+=val;
126                 }
127                 else if(pl==2&&pu==1)
128                 {
129                     state=renew(state,l+1,0);
130                     state=renew(state,l,0);
131                     addstate(state,val);
132                 }
133                 else if(pl==1&&pu==1)
134                 {
135                     int pos=fr1to2(state,l+1);
136                     state=renew(state,l+1,0);
137                     state=renew(state,l,0);
138                     state=renew(state,pos,1);
139                     addstate(state,val);
140                 }
141                 else if(pl==2&&pu==2)
142                 {
143                     int pos=fr2to1(state,l);
144                     state=renew(state,l+1,0);
145                     state=renew(state,l,0);
146                     state=renew(state,pos,2);
147                     addstate(state,val);
148                 }
149             }
150             alans=ans;
151             break;
152         }
153         case '-':{
154             for(int i=0;i<sta[now].size();++i)
155             {
156                 state=sta[now][i];
157                 val=getval(state);
158                 pl=get(state,l);
159                 pu=get(state,l+1);
160                 pr(state);
161                 if(pl&&!pu)
162                 {
163                     state=renew(state,l+1,pl);
164                     state=renew(state,l,0);
165                     addstate(state,val);
166                 }
167             }
168             break;
169         }
170         case '|':{
171             for(int i=0;i<sta[now].size();++i)
172             {
173                 state=sta[now][i];
174                 val=getval(state);
175                 pl=get(state,l);
176                 pu=get(state,l+1);
177                 if(!pl&&pu)
178                 {
179                     state=renew(state,l,pu);
180                     state=renew(state,l+1,0);
181                     addstate(state,val);
182                 }
183             }
184             break;
185         }
186         case '#':{
187             for(int i=0;i<sta[now].size();++i)
188             {
189                 state=sta[now][i];
190                 val=getval(state);
191                 pl=get(state,l);
192                 pu=get(state,l+1);
193                 if(!pl&&!pu)addstate(state,val);
194             }
195             break;
196         }
197     }
198 }
199 void reset()//换行/行间转移
200 {
201     int state;ll val;
202     now^=1;to^=1;
203     memset(he[to],0,sizeof(he[to]));sta[to].clear();
204     for(int i=0;i<sta[now].size();++i)
205     {
206         state=sta[now][i];
207         val=getval(state);
208         if(get(state,m+1))continue;
209         addstate(state<<2,val);
210     }
211 }
212 int main()
213 {
214     scanf("%d%d",&n,&m);
215     to=1;now=0;
216     addstate(0,1);
217     for(int i=1;i<=n;++i)
218     {
219         scanf("%s",s+1);
220         for(int j=1;j<=m;++j)work(i,j);
221         reset();
222     }
223     cout<<alans<<endl;
224 }

 其实这份代码并不完美,它会搜索一些冗余状态,导致程序跑得比较慢,对于极强的数据很容易被卡,正常题一般都能水过

 

以上为模板,然而我早就不用这套了。。

插头dp的题核心就在于插头的设计,以及两插头相撞时的处理方式。

插头dp码长好像都挺长,其实都出在了撞插头时的分类讨论以及各种各样的状态处理函数。

题方面的话,插头dp对思路要求不太高,就是恶心。一般会给你一个矩阵,或图之类的,一般行数都挺多,但列数范围不大

在做一些网格题时插头dp可以用来拿部分分。

然后:

学习博客:https://www.cnblogs.com/LadyLex/p/7326874.html

题目总结:https://www.cnblogs.com/Lrefrain/p/12004519.html

插头dp就这么多,可能还是我做题少吧,以后刷的题多了,理解深刻了可能还会再更。

posted @ 2019-12-18 21:30  真-不能AKt♞  阅读(379)  评论(0编辑  收藏  举报