bzoj1814: Ural 1519 Formula 1 动态规划 插头dp
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的更多相关文章
- bzoj1814 Ural 1519 Formula 1(插头DP)
对插头DP的理解还不是很透彻. 先说一下肤浅的理解吧. 插头DP使用范围:指数级复杂度,且适用于解决网格图连通性问题,如哈密顿回路等问题.插头一般指每相邻2个网格的接口. 题目难度:一般不可做. 使用 ...
- 插头DP讲解+[BZOJ1814]:Ural 1519 Formula 1(插头DP)
1.什么是插头$DP$? 插头$DP$是$CDQ$大佬在$2008$年的论文中提出的,是基于状压$D$P的一种更高级的$DP$多用于处理联通问题(路径问题,简单回路问题,多回路问题,广义回路问题,生成 ...
- 【BZOJ1814】Ural 1519 Formula 1 (插头dp)
[BZOJ1814]Ural 1519 Formula 1 (插头dp) 题面 BZOJ Vjudge 题解 戳这里 上面那个链接里面写的非常好啦. 然后说几个点吧. 首先是关于为什么只需要考虑三进制 ...
- URAL 1519 Formula 1(插头DP,入门题)
Description Background Regardless of the fact, that Vologda could not get rights to hold the Winter ...
- ural 1519 Formula 1(插头dp)
1519. Formula 1 @ Timus Online Judge 干了一天啊!!!插头DP入门. 代码如下: #include <cstdio> #include <cstr ...
- HDU 1693 Eat the Trees(插头DP、棋盘哈密顿回路数)+ URAL 1519 Formula 1(插头DP、棋盘哈密顿单回路数)
插头DP基础题的样子...输入N,M<=11,以及N*M的01矩阵,0(1)表示有(无)障碍物.输出哈密顿回路(可以多回路)方案数... 看了个ppt,画了下图...感觉还是挺有效的... 参考 ...
- URAL 1519 Formula 1 (插头DP,常规)
题意:给一个n*m的矩阵,格子中是'*'则是障碍格子,不允许进入,其他格子都是必走的格子,所走格子形成一条哈密顿回路,问有多少种走法? 思路: 本来是很基础的题,顿时不知道进入了哪个坑.这篇插头DP的 ...
- bzoj 1814: Ural 1519 Formula 1【插头dp】
设f[i][j][s]为轮廓线推到格子(i,j),状态为s的方案数 括号表示一段线的左端和右端,表示成左括号和右括号,状压的时候用1和2表示,0表示已经闭合 下面的蓝线是黄色格子的轮廓线,dp转移要把 ...
- bzoj1814 Ural 1519 Formula 1(插头dp模板题)
1814: Ural 1519 Formula 1 Time Limit: 1 Sec Memory Limit: 64 MBSubmit: 924 Solved: 351[Submit][Sta ...
随机推荐
- React Native新手入门
前言 React Native是最近非常火的一个话题,想要学习如何使用它,首先就要知道它是什么. 好像面对一个新手全面介绍它的文章还不多,我就归纳一下所有的资料和刚入门的小伙伴一起来认识它~ 将从以下 ...
- 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 ...
- Android音视频点/直播模块开发实践总结-zz
随着音视频领域的火热,在很多领域(教育,游戏,娱乐,体育,跑步,餐饮,音乐等)尝试做音视频直播/点播功能.那么作为开发一个小白,如何快速学习音视频基础知识,了解音视频编解码的传输协议,编解码方式,以及 ...
- python的面对对象
创建类 使用 class 语句来创建一个新类,class 之后为类的名称并以冒号结尾: class ClassName: '类的帮助信息' #类文档字符串 class_suite #类体 类的帮助信息 ...
- JDK1.8源码之String
一.String类型 引用博文连接: https://blog.csdn.net/ylyg050518/article/details/52352993 一.成员变量 //用于存储字符串 priva ...
- ClientDataset 三层 var and out arguments must match parameter
将Delphi升级到10.1.2后,从客户端传ClientDataset的Delta数据到服务端程序时,出现var and out arguments must match parameter错 ...
- Android 抽屉导航
原文地址 http://developer.android.com/training/implementing-navigation/nav-drawer.html 创建抽屉导航 导航抽屉是在 屏幕左 ...
- Python基础:内置异常(未完待续)
本文根据Python 3.6.5的官文Built-in Exceptions编写,不会很详细,仅对Python的内置异常进行简单(重难点)介绍——很多异常都可以从名称判断出其意义,罗列所有的内置异常. ...
- 国内能用的NTP服务器及和标准源的偏差值
中国境内可以使用的NTP服务器的IP地址,和泰福特服务器的时间偏差值,泰福特时钟服务器实时连接天线,测试前已经连接天线超过72小时 time-a.nist.gov 129.6.15.28 NIST, ...
- ubuntu 创建容器 并ssh 连接容器
1.下载镜像:docker search ubuntu docker pull ubuntu 2. 创建容器 docker run --name spider_frame -p 8888:8888 - ...