• 动态规划:插头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 }
  • 相关阅读:
    H5移动前端完美布局之-margin百分比的使用
    javascript 一个关于时间排序的算法(一个页面多个倒计时排序)
    html5 getComputedStyle + resize 实现动态宽高度等比响应式页面设计
    Windows 下关于转码的函数
    项目编译完之后自动提交
    eclipse 包含头文件出错
    Eclipse 包含头文件 添加环境变量
    linux下mongodb程序和c++客户端的编译
    简单谈谈消息发送缓冲区
    epoll 性能分析(解决占用CPU 过高问题)2
  • 原文地址:https://www.cnblogs.com/aininot260/p/9627200.html
Copyright © 2020-2023  润新知