动态规划:插头DP

这种动归有很多名字,插头DP是最常见的

还有基于连通性的动态规划

轮廓线动态规划等等

超小数据范围,网格图,连通性

可能算是状态压缩DP的一种变式

以前我了解的状压DP用于NP难题的小数据范围求解

这里说一下哈密顿回路的概念:

哈密顿回路: 
1、指一个对图的每个顶点都只穿越一次的回路。也可以 定义为n+1个相邻顶点v0, v1, … ,vn, v0的一个序列,其中序列的第一个顶点和最后一个顶点是相同的,而其他n-1个顶点是互不相同的。 
2、当这个图是加权图时,求该图的最短哈密顿回路,就是传说中的旅行商问题(TSP)。

然后是一道插头DP的入门题

一个网格图中有若干障碍格子,求其他格子的哈密尔顿回路总数

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 const int LIM=300005,Has=299989;
 5 int n,m,e1,e2,las,now,tt;LL ans;
 6 int mp[15][15],bin[15],tot[2];LL js[2][LIM];
 7 int h[300005],a[2][LIM],ne[LIM];
 8 //tot:状态总数,js:该状态的方案总数,a:各种状态
 9 void ins(int zt,LL num) {//卓越的哈希技术
10     int tmp=zt%Has+1;
11     for(int i=h[tmp];i;i=ne[i])
12         if(a[now][i]==zt) {js[now][i]+=num;return;}
13     ne[++tot[now]]=h[tmp],h[tmp]=tot[now];
14     a[now][tot[now]]=zt,js[now][tot[now]]=num;
15 }
16 void work() {
17     tot[now]=1,js[now][1]=1,a[now][1]=0;
18     for(int i=1;i<=n;++i) {
19         for(int j=1;j<=tot[now];++j) a[now][j]<<=2;//切换行了
20         for(int j=1;j<=m;++j) {
21             las=now,now^=1;
22             memset(h,0,sizeof(h)),tot[now]=0;
23             for(int k=1;k<=tot[las];++k) {
24                 int zt=a[las][k],b1=(zt>>(j*2-2))%4,b2=(zt>>(j*2))%4;//提取关键格子上的两段轮廓线状态
25                 LL num=js[las][k];
26                 if(!mp[i][j]) {if(!b1&&!b2) ins(zt,num);}
27                 else if(!b1&&!b2) 
28                     {if(mp[i+1][j]&&mp[i][j+1]) ins(zt+bin[j-1]+2*bin[j],num);}
29                 else if(!b1&&b2) {
30                     if(mp[i][j+1]) ins(zt,num);
31                     if(mp[i+1][j]) ins(zt-bin[j]*b2+bin[j-1]*b2,num);
32                 }
33                 else if(b1&&!b2) {
34                     if(mp[i][j+1]) ins(zt-bin[j-1]*b1+bin[j]*b1,num);
35                     if(mp[i+1][j]) ins(zt,num);
36                 }
37                 else if(b1==1&&b2==1) {
38                     int kl=1;
39                     for(int t=j+1;t<=m;++t) {
40                         if((zt>>(t*2))%4==1) ++kl;
41                         if((zt>>(t*2))%4==2) --kl;
42                         if(!kl) {ins(zt-bin[j]-bin[j-1]-bin[t],num);break;}
43                     }
44                 }
45                 else if(b1==2&&b2==2) {
46                     int kl=1;
47                     for(int t=j-2;t>=0;--t) {
48                         if((zt>>(t*2))%4==1) --kl;
49                         if((zt>>(t*2))%4==2) ++kl;
50                         if(!kl) {ins(zt+bin[t]-2*bin[j]-2*bin[j-1],num);break;}
51                     }
52                 }
53                 else if(b1==2&&b2==1) ins(zt-2*bin[j-1]-bin[j],num);
54                 else if(i==e1&&j==e2) ans+=num;
55             }
56         }
57     }
58 }
59 int main()
60 {
61     scanf("%d%d",&n,&m);
62     for(int i=1;i<=n;++i)
63         for(int j=1;j<=m;++j) {
64         char ch=getchar();
65         while(ch!='*'&&ch!='.') ch=getchar();
66         if(ch=='.') mp[i][j]=1,e1=i,e2=j;
67     }
68     bin[0]=1;for(int i=1;i<=12;++i) bin[i]=bin[i-1]<<2;
69     work(),printf("%lld
",ans);
70     return 0;
71 }

然后是HDU1693

给一个n*m的地图,有些格子是不可到达的,要把所有可到达的格子的树都吃完,并且要走回路,求方案数

允许有多个回路,找一条或多条回路,吃完所有的树

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 int n,m,T,kas,bin[15],mp[15][15];LL f[12][12][(1<<12)];
 5 int main()
 6 {
 7     scanf("%d",&T);
 8     bin[0]=1;for(int i=1;i<=12;++i) bin[i]=bin[i-1]<<1;
 9     while(T--) {
10         scanf("%d%d",&n,&m);
11         for(int i=1;i<=n;++i)
12             for(int j=1;j<=m;++j) scanf("%d",&mp[i][j]);
13         memset(f,0,sizeof(f));
14         f[0][m][0]=1;int lim=bin[m+1]-1;
15         for(int i=1;i<=n;++i) {
16             for(int zt=0;zt<=lim;++zt) f[i][0][zt<<1]=f[i-1][m][zt];
17             for(int j=1;j<=m;++j)
18             for(int zt=0;zt<=lim;++zt) {
19             int b1=zt&bin[j-1],b2=zt&bin[j];LL num=f[i][j-1][zt];
20             if(!mp[i][j]) {if(!b1&&!b2) f[i][j][zt]+=num;}
21             else if(!b1&&!b2) 
22             {if(mp[i][j+1]&&mp[i+1][j])f[i][j][zt+bin[j-1]+bin[j]]+=num;}
23             else if(!b1&&b2) {
24                 if(mp[i][j+1]) f[i][j][zt]+=num;
25                 if(mp[i+1][j]) f[i][j][zt-bin[j]+bin[j-1]]+=num;
26             }
27             else if(b1&&!b2) {
28                 if(mp[i][j+1]) f[i][j][zt-bin[j-1]+bin[j]]+=num;
29                 if(mp[i+1][j]) f[i][j][zt]+=num;
30             }
31             else f[i][j][zt-bin[j-1]-bin[j]]+=num;
32         }
33         }
34         printf("Case %d: There are %lld ways to eat the trees.
",++kas,f[n][m][0]);
35     }
36     return 0;
37 }
原文地址:https://www.cnblogs.com/aininot260/p/9627200.html