http://acm.timus.ru/problem.aspx?space=1&num=1519

题目描述

一个 m * n 的棋盘,有的格子存在障碍,求经过所有非障碍格子的哈密顿回路个数。

输入

The first line contains the integer numbers N and M (2 ≤ N, M ≤ 12). Each of the next N lines contains M characters, which are the corresponding cells of the rectangle. Character "." (full stop) means a cell, where a segment of the race circuit should be built, and character "*" (asterisk) - a cell, where a gopher hole is located.

输出

You should output the desired number of ways. It is guaranteed, that it does not exceed 2^63-1.

样例输入

4 4
**..
....
....
....

样例输出

2

直接写时间复杂度过不了,直接写了个dp里面有很多无用状态,剪枝一下(存下一个的有用状态)就行了。

 #include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<map>
using namespace std;
#define LL long long
int n,m;
char ch[][]={};
int id[][]={};
LL shu[]={};
map< int,LL >f[];
inline int getit(int z,int i){return (z/shu[i])%;}
int main(){
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)scanf("%s",ch[i]+);
for(int i=;i<=n;i++)for(int j=;j<=m;j++)id[i][j]=(i-)*m+j;
shu[]=;int ff=;
for(int i=;i<=m+;i++)shu[i]=shu[i-]*;
if(ch[][]=='.'){f[][+*]=;ff=;}
else f[][]=;
int mx=shu[m+]*,now,nex,fla,z,x,y; LL val;
for(int i=;i<=n;i++){
for(int j=;j<m;j++){
if(i==n&&j==m-)break;
now=id[i][j];nex=now+;fla=;
if(ch[i][j+]!='.')fla=;
if(ch[i][j]==)ff=;
for(int w=ff;w<mx;w++){
val=f[now][w];
if(val==)continue;
x=getit(w,j+);y=getit(w,j+);
if(fla){
if(x==&&y==){
z=w+(-x)*shu[j+]+(-y)*shu[j+];
f[nex][z]+=val;
}
continue;
}
if(x==&&y==){
z=w+(-x)*shu[j+]+(-y)*shu[j+];
f[nex][z]+=val;
}
else if(x==||y==){
z=w+(x+y-x)*shu[j+]+(-y)*shu[j+];
f[nex][z]+=val;
z=w+(-x)*shu[j+]+(x+y-y)*shu[j+];
f[nex][z]+=val;
}
else if(x==y){
z=w+(-x)*shu[j+]+(-y)*shu[j+];
int zz,zzz;
if(x==){
zz=-;zzz=j+;
while(zz!=){
++zzz;
if(zzz>m+)break;
if(getit(w,zzz)==)--zz;
if(getit(w,zzz)==) ++zz;
}
if(zz!=)continue;
z=z+(-)*shu[zzz];
}
else{
zz=;zzz=j+;
while(zz!=){
--zzz;
if(zzz>m+)break;
if(getit(w,zzz)==)--zz;
if(getit(w,zzz)==) ++zz;
}
if(zz!=)continue;
z=z+(-)*shu[zzz];
}
f[nex][z]+=val;
}
else if(x==&&y==){
z=w+(-x)*shu[j+]+(-y)*shu[j+];
f[nex][z]+=val;
}
}
}
if(i==n)break;
now=i*m;nex=now+;
fla=;
if(ch[i+][]!='.')fla=;
if(ch[i][m]=='.')ff=;
for(int w=ff;w<mx;++w){
val=f[now][w];
if(val==)continue;
if(getit(w,m+)!=)continue;
x=getit(w,);
if(fla){
if(!x){
z=(w%shu[m+]-x)*; f[nex][z]+=val;
}
continue;
}
if(x==){
z=(w%shu[m+]-x)*;
z=z+;f[nex][z]+=val;
z=z+;f[nex][z]+=val;
}
else if(x==){
z=(w%shu[m+]-x)*++*;
f[nex][z]+=val;
}
}
}
printf("%lld\n",f[n*m-][shu[m]*+shu[m+]*]);
return ;
}

原代码

更改之后不开O2跑12*12的无障碍图需要快2s,大概是用map复杂度加了个log的锅……不想写hash……

 #include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<map>
using namespace std;
#define LL long long
int n,m;
char ch[][]={};
int id[][]={};
int cun[][]={},tot[]={};
LL shu[]={};
map< int,LL >f[];
inline int getit(int z,int i){return (z/shu[i])%;}
int main(){
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)scanf("%s",ch[i]+);
for(int i=;i<=n;i++)for(int j=;j<=m;j++)id[i][j]=(i-)*m+j;
shu[]=;
for(int i=;i<=m+;i++)shu[i]=shu[i-]*;
if(ch[][]=='.'){f[][+*]=;tot[]=;cun[][]=+*;}
else { f[][]=;tot[]=;cun[][]=;}
int now,nex,fla,z,x,y,id1,id2; LL val;
for(int i=;i<=n;i++){
for(int j=;j<m;j++){
if(i==n&&j==m-)break;
now=id[i][j];nex=now+;fla=;
if(ch[i][j+]!='.')fla=;
id1=id[i][j]&;id2=id1^;
tot[id2]=;
for(int k=;k<=tot[id1];k++){
int w=cun[id1][k];
val=f[now][w];
if(val==)continue;
x=getit(w,j+);y=getit(w,j+);
if(fla){
if(x==&&y==){
z=w+(-x)*shu[j+]+(-y)*shu[j+];
if(f[nex][z]==)cun[id2][++tot[id2]]=z;
f[nex][z]+=val;
}
continue;
}
if(x==&&y==){
z=w+(-x)*shu[j+]+(-y)*shu[j+];
if(f[nex][z]==)cun[id2][++tot[id2]]=z;
f[nex][z]+=val;
}
else if(x==||y==){
z=w+(x+y-x)*shu[j+]+(-y)*shu[j+];
if(f[nex][z]==)cun[id2][++tot[id2]]=z;
f[nex][z]+=val;
z=w+(-x)*shu[j+]+(x+y-y)*shu[j+];
if(f[nex][z]==)cun[id2][++tot[id2]]=z;
f[nex][z]+=val;
}
else if(x==y){
z=w+(-x)*shu[j+]+(-y)*shu[j+];
int zz,zzz;
if(x==){
zz=-;zzz=j+;
while(zz!=){
++zzz;
if(zzz>m+)break;
if(getit(w,zzz)==)--zz;
if(getit(w,zzz)==) ++zz;
}
if(zz!=)continue;
z=z+(-)*shu[zzz];
}
else{
zz=;zzz=j+;
while(zz!=){
--zzz;
if(zzz>m+)break;
if(getit(w,zzz)==)--zz;
if(getit(w,zzz)==) ++zz;
}
if(zz!=)continue;
z=z+(-)*shu[zzz];
}
if(f[nex][z]==)cun[id2][++tot[id2]]=z;
f[nex][z]+=val;
}
else if(x==&&y==){
z=w+(-x)*shu[j+]+(-y)*shu[j+];
if(f[nex][z]==)cun[id2][++tot[id2]]=z;
f[nex][z]+=val;
}
}
}
if(i==n)break;
now=i*m;nex=now+;
fla=;
if(ch[i+][]!='.')fla=;
id1=id[i][m]&;id2=id1^;
tot[id2]=;
for(int k=;k<=tot[id1];++k){
int w=cun[id1][k];
val=f[now][w];
if(val==)continue;
if(getit(w,m+)!=)continue;
x=getit(w,);
if(fla){
if(!x){
z=(w%shu[m+]-x)*;
if(f[nex][z]==)cun[id2][++tot[id2]]=z;
f[nex][z]+=val;
}
continue;
}
if(x==){
z=(w%shu[m+]-x)*;
z=z+; if(f[nex][z]==)cun[id2][++tot[id2]]=z;
f[nex][z]+=val;
z=z+; if(f[nex][z]==)cun[id2][++tot[id2]]=z;
f[nex][z]+=val;
}
else if(x==){
z=(w%shu[m+]-x)*++*;
if(f[nex][z]==)cun[id2][++tot[id2]]=z;
f[nex][z]+=val;
}
}
}
printf("%lld\n",f[n*m-][shu[m]*+shu[m+]*]);
return ;
}

去掉无用状态后

用map竟然过了……不过要注意一下最后输出的是最后一个可行位置的答案,很有可能最后一个点不是可行的,被坑了一下QAQ

 #include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<map>
using namespace std;
#define LL long long
int n,m;
char ch[][]={};
int id[][]={};
int cun[][]={},tot[]={};
LL shu[]={};
map< int,LL >f[];
inline int getit(int z,int i){return (z/shu[i])%;}
int main(){
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)scanf("%s",ch[i]+);
for(int i=;i<=n;i++)for(int j=;j<=m;j++)id[i][j]=(i-)*m+j;
int idx=,idy=;
for(int i=;i<=n;i++)for(int j=;j<=m;j++)if(ch[i][j]=='.'){idx=i;idy=j;}
if(idy<=){printf("0\n");return ;}
shu[]=;
for(int i=;i<=m+;i++)shu[i]=shu[i-]*;
if(ch[][]=='.'){f[][+*]=;tot[]=;cun[][]=+*;}
else { f[][]=;tot[]=;cun[][]=;}
int now,nex,fla,z,x,y,id1,id2; LL val;
for(int i=;i<=idx;i++){
for(int j=;j<m;j++){
if(i==n&&j==m-)break;
now=id[i][j];nex=now+;fla=;
if(ch[i][j+]!='.')fla=;
id1=id[i][j]&;id2=id1^;
tot[id2]=;
for(int k=;k<=tot[id1];k++){
int w=cun[id1][k];
val=f[now][w];
if(val==)continue;
x=getit(w,j+);y=getit(w,j+);
if(fla){
if(x==&&y==){
z=w+(-x)*shu[j+]+(-y)*shu[j+];
if(f[nex][z]==)cun[id2][++tot[id2]]=z;
f[nex][z]+=val;
}
continue;
}
if(x==&&y==){
z=w+(-x)*shu[j+]+(-y)*shu[j+];
if(f[nex][z]==)cun[id2][++tot[id2]]=z;
f[nex][z]+=val;
}
else if(x==||y==){
z=w+(x+y-x)*shu[j+]+(-y)*shu[j+];
if(f[nex][z]==)cun[id2][++tot[id2]]=z;
f[nex][z]+=val;
z=w+(-x)*shu[j+]+(x+y-y)*shu[j+];
if(f[nex][z]==)cun[id2][++tot[id2]]=z;
f[nex][z]+=val;
}
else if(x==y){
z=w+(-x)*shu[j+]+(-y)*shu[j+];
int zz,zzz;
if(x==){
zz=-;zzz=j+;
while(zz!=){
++zzz;
if(zzz>m+)break;
if(getit(w,zzz)==)--zz;
if(getit(w,zzz)==) ++zz;
}
if(zz!=)continue;
z=z+(-)*shu[zzz];
}
else{
zz=;zzz=j+;
while(zz!=){
--zzz;
if(zzz>m+)break;
if(getit(w,zzz)==)--zz;
if(getit(w,zzz)==) ++zz;
}
if(zz!=)continue;
z=z+(-)*shu[zzz];
}
if(f[nex][z]==)cun[id2][++tot[id2]]=z;
f[nex][z]+=val;
}
else if(x==&&y==){
z=w+(-x)*shu[j+]+(-y)*shu[j+];
if(f[nex][z]==)cun[id2][++tot[id2]]=z;
f[nex][z]+=val;
}
}
}
if(i==n)break;
now=i*m;nex=now+;
fla=;
if(ch[i+][]!='.')fla=;
id1=id[i][m]&;id2=id1^;
tot[id2]=;
for(int k=;k<=tot[id1];++k){
int w=cun[id1][k];
val=f[now][w];
if(val==)continue;
if(getit(w,m+)!=)continue;
x=getit(w,);
if(fla){
if(!x){
z=(w%shu[m+]-x)*;
if(f[nex][z]==)cun[id2][++tot[id2]]=z;
f[nex][z]+=val;
}
continue;
}
if(x==){
z=(w%shu[m+]-x)*;
z=z+; if(f[nex][z]==)cun[id2][++tot[id2]]=z;
f[nex][z]+=val;
z=z+; if(f[nex][z]==)cun[id2][++tot[id2]]=z;
f[nex][z]+=val;
}
else if(x==){
z=(w%shu[m+]-x)*++*;
if(f[nex][z]==)cun[id2][++tot[id2]]=z;
f[nex][z]+=val;
}
}
}
printf("%lld\n",f[(idx-)*m+idy-][shu[idy]*+shu[idy+]*]);
return ;
}

这绝对是最后一版了

cnblog什么毛病啊……给代码加了标题如果要复制代码标题就到代码末尾了……mdzz

bzoj1814: Ural 1519 Formula 1 动态规划 插头dp的更多相关文章

  1. bzoj1814 Ural 1519 Formula 1(插头DP)

    对插头DP的理解还不是很透彻. 先说一下肤浅的理解吧. 插头DP使用范围:指数级复杂度,且适用于解决网格图连通性问题,如哈密顿回路等问题.插头一般指每相邻2个网格的接口. 题目难度:一般不可做. 使用 ...

  2. 插头DP讲解+[BZOJ1814]:Ural 1519 Formula 1(插头DP)

    1.什么是插头$DP$? 插头$DP$是$CDQ$大佬在$2008$年的论文中提出的,是基于状压$D$P的一种更高级的$DP$多用于处理联通问题(路径问题,简单回路问题,多回路问题,广义回路问题,生成 ...

  3. 【BZOJ1814】Ural 1519 Formula 1 (插头dp)

    [BZOJ1814]Ural 1519 Formula 1 (插头dp) 题面 BZOJ Vjudge 题解 戳这里 上面那个链接里面写的非常好啦. 然后说几个点吧. 首先是关于为什么只需要考虑三进制 ...

  4. URAL 1519 Formula 1(插头DP,入门题)

    Description Background Regardless of the fact, that Vologda could not get rights to hold the Winter ...

  5. ural 1519 Formula 1(插头dp)

    1519. Formula 1 @ Timus Online Judge 干了一天啊!!!插头DP入门. 代码如下: #include <cstdio> #include <cstr ...

  6. HDU 1693 Eat the Trees(插头DP、棋盘哈密顿回路数)+ URAL 1519 Formula 1(插头DP、棋盘哈密顿单回路数)

    插头DP基础题的样子...输入N,M<=11,以及N*M的01矩阵,0(1)表示有(无)障碍物.输出哈密顿回路(可以多回路)方案数... 看了个ppt,画了下图...感觉还是挺有效的... 参考 ...

  7. URAL 1519 Formula 1 (插头DP,常规)

    题意:给一个n*m的矩阵,格子中是'*'则是障碍格子,不允许进入,其他格子都是必走的格子,所走格子形成一条哈密顿回路,问有多少种走法? 思路: 本来是很基础的题,顿时不知道进入了哪个坑.这篇插头DP的 ...

  8. bzoj 1814: Ural 1519 Formula 1【插头dp】

    设f[i][j][s]为轮廓线推到格子(i,j),状态为s的方案数 括号表示一段线的左端和右端,表示成左括号和右括号,状压的时候用1和2表示,0表示已经闭合 下面的蓝线是黄色格子的轮廓线,dp转移要把 ...

  9. bzoj1814 Ural 1519 Formula 1(插头dp模板题)

    1814: Ural 1519 Formula 1 Time Limit: 1 Sec  Memory Limit: 64 MBSubmit: 924  Solved: 351[Submit][Sta ...

随机推荐

  1. React Native新手入门

    前言 React Native是最近非常火的一个话题,想要学习如何使用它,首先就要知道它是什么. 好像面对一个新手全面介绍它的文章还不多,我就归纳一下所有的资料和刚入门的小伙伴一起来认识它~ 将从以下 ...

  2. Red Hat Enterprise Linux 7.2下使用RPM包安装SQL Server vNext

    1.下载安装包 mssql-server:https://packages.microsoft.com/rhel/7/mssql-server/ mssql-tools:https://package ...

  3. Android音视频点/直播模块开发实践总结-zz

    随着音视频领域的火热,在很多领域(教育,游戏,娱乐,体育,跑步,餐饮,音乐等)尝试做音视频直播/点播功能.那么作为开发一个小白,如何快速学习音视频基础知识,了解音视频编解码的传输协议,编解码方式,以及 ...

  4. python的面对对象

    创建类 使用 class 语句来创建一个新类,class 之后为类的名称并以冒号结尾: class ClassName: '类的帮助信息' #类文档字符串 class_suite #类体 类的帮助信息 ...

  5. JDK1.8源码之String

    一.String类型 引用博文连接:  https://blog.csdn.net/ylyg050518/article/details/52352993 一.成员变量 //用于存储字符串 priva ...

  6. ClientDataset 三层 var and out arguments must match parameter

    ​​​将Delphi升级到10.1.2后,从客户端传ClientDataset的Delta数据到服务端程序时,出现var and out arguments must match parameter错 ...

  7. Android 抽屉导航

    原文地址 http://developer.android.com/training/implementing-navigation/nav-drawer.html 创建抽屉导航 导航抽屉是在 屏幕左 ...

  8. Python基础:内置异常(未完待续)

    本文根据Python 3.6.5的官文Built-in Exceptions编写,不会很详细,仅对Python的内置异常进行简单(重难点)介绍——很多异常都可以从名称判断出其意义,罗列所有的内置异常. ...

  9. 国内能用的NTP服务器及和标准源的偏差值

    中国境内可以使用的NTP服务器的IP地址,和泰福特服务器的时间偏差值,泰福特时钟服务器实时连接天线,测试前已经连接天线超过72小时 time-a.nist.gov 129.6.15.28 NIST, ...

  10. ubuntu 创建容器 并ssh 连接容器

    1.下载镜像:docker search ubuntu docker pull ubuntu 2. 创建容器 docker run --name spider_frame -p 8888:8888 - ...