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

题目分类:插头dp

题意:求经过所有可行点的哈密顿回路的个数  * 不可走 . 可以走  2 ≤ NM ≤ 12

代码:

括号匹配法,转移有点复杂,但是时间空间比较小 

#include<bits/stdc++.h>

#define LL long long
using namespace std;
const int maxn=;
int n,m,now,pre;
int mov[]={,,,,,,,,,,,,};//根据进制选择移位距离
char gp[][],fx,fy;//存图,最后一个可行点的坐标
inline int getbit(LL st,int k){ return (st>>mov[k])&;}//获得第k位的状态
inline int pybit(LL st,int k){ return st<<mov[k];} //平移k位
inline LL clrbit(LL st,int i,int j){ return st&(~(<<mov[i]))&(~(<<mov[j]));}//清空第i位和第j位
struct node//状态离散hash
{
int head[maxn],next[maxn],size;
LL sum[maxn],sta[maxn];//保存所求和及状态
void clear()
{
memset(head,-,sizeof(head));
memset(sum,,sizeof(sum));
size=;
}
void push(LL st,const LL v)
{
LL hash=st%maxn;
for(int i=head[hash];i>=;i=next[i])
{
if(sta[i]==st)
{
sum[i]+=v;
return;
}
}
sta[size]=st,sum[size]=v;
next[size]=head[hash],head[hash]=size++;
}
}dp[];
inline int fl(LL st,int pos)//从左往右找到和当前pos位置匹配的右括号
{
int cnt=;
for(int i=pos+;i<=m;i++)
{
int k=getbit(st,i);
if(k==) cnt++;
else if(k==) cnt--;
if(!cnt) return i;
}
}
inline int fr(LL st,int pos)//从右往左找到和当前pos位置匹配的左括号
{
int cnt=;
for(int i=pos-;i>=;i--)
{
int k=getbit(st,i);
if(k==) cnt++;
else if(k==) cnt--;
if(!cnt) return i;
}
}
void DP(int x,int y,int k)//每种状态的转移,根据需要修改
{
int l=getbit(dp[pre].sta[k],y-);
int up=getbit(dp[pre].sta[k],y);
LL st=clrbit(dp[pre].sta[k],y-,y);
LL v=dp[pre].sum[k];
if(!l&&!up)
{
if(gp[x][y]=='*')
{
dp[now].push(st,v);
return;
}
if(x<n&&y<m&&gp[x+][y]=='.'&&gp[x][y+]=='.')
dp[now].push(st|pybit(,y-)|pybit(,y),v);
}
else if(!l||!up)
{
int e=l+up;
if(x<n&&gp[x+][y]=='.')
dp[now].push(st|pybit(e,y-),v);
if(y<m&&gp[x][y+]=='.')
dp[now].push(st|pybit(e,y),v);
}
else if(l==&&up==)
dp[now].push(st^pybit(,fl(st,y)),v);
else if(l==&&up==)
dp[now].push(st^pybit(,fr(st,y-)),v);
else if(l==&&up==)
dp[now].push(st,v);
else if(x==fx&&y==fy)
dp[now].push(st,v);
}
LL solve()
{
dp[].clear();//初状态
dp[].push(,);
now=,pre=;
for(int i=;i<=n;i++)//逐格逐状态枚举
{
pre=now,now^=,dp[now].clear();
for(int k=;k<dp[pre].size;k++)//轮廓线下移对齐
dp[now].push(pybit(dp[pre].sta[k],),dp[pre].sum[k]);
for(int j=;j<=m;j++)
{
pre=now,now^=,dp[now].clear();
for(int k=;k<dp[pre].size;k++)
{
DP(i,j,k);
}
}
}
for(int i=;i<dp[now].size;i++)//寻找最终答案
if(dp[now].sta[i]==)
return dp[now].sum[i];
return ;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
for(int i=;i<=n;i++)//都是从1开始的
scanf("%s",&gp[i][]);
fx=;
for(int i=n;i>&&!fx;i--)//寻找最后一个可行点
{
for(int j=m;j>&&!fx;j--)
{
if(gp[i][j]=='.')
fx=i,fy=j;
}
}
if(fx==) puts("");
else cout<<solve()<<endl;
}
return ;
}

最小表示法,转移简单,时间空间较大

#include<bits/stdc++.h>

#define LL long long
using namespace std;
const int maxn=,inc=,bit=;//3位二进制以及111的表示
int n,m,now,pre,code[],bin[],res[];//用来表示状态的每一位的数值
char gp[][],fx,fy;//图和最后的可行点
struct node//离散化hash
{
int head[maxn],next[maxn],size;
LL sum[maxn],sta[maxn];
void clear()
{
memset(head,-,sizeof(head));
size=;
}
void push(LL st,const LL v)
{
LL hash=st%maxn;
for(int i=head[hash];i>=;i=next[i])
{
if(sta[i]==st)
{
sum[i]+=v;
return ;
}
}
sta[size]=st,sum[size]=v;
next[size]=head[hash],head[hash]=size++;
}
}dp[];
inline LL encode(int m)//将code转换成状态
{
LL st=;
int cnt=;
memset(bin,-,sizeof(bin));
bin[]=;
for(int i=m;i>=;i--)
{
if(bin[code[i]]==-)
bin[code[i]]=cnt++;
code[i]=bin[code[i]];
st<<=inc;
st|=code[i];
}
return st;
}
inline void decode(LL st,int m)//将状态转换成code
{
for(int i=;i<=m;i++)
{
code[i]=st&bit;
st>>=inc;
}
}
void DP(int x,int y,int k)//dp具体情况具体分析
{
decode(dp[pre].sta[k],m);
int l=code[y-];
int up=code[y];
code[y-]=code[y]=;
memcpy(res,code,sizeof(code));
LL v=dp[pre].sum[k];
if(!l&&!up)
{
if(gp[x][y]=='*')
dp[now].push(encode(m),v);
else if(x<n&&y<m&&gp[x+][y]=='.'&&gp[x][y+]=='.')
{
code[y]=code[y-]=bit;
dp[now].push(encode(m),v);
}
}
else if(!l||!up)
{
int e=l+up;
if(x<n&&gp[x+][y]=='.')
{
code[y-]=e;
dp[now].push(encode(m),v);
memcpy(code,res,sizeof(res));
}
if(y<m&&gp[x][y+]=='.')
{
code[y]=e;
dp[now].push(encode(m),v);
}
}
else if(l!=up)
{
for(int i=;i<=m;i++)
if(code[i]==up)
code[i]=l;
dp[now].push(encode(m),v);
}
else if(x==fx&&y==fy)
dp[now].push(encode(m),v);
}
LL solve()
{
dp[].clear();//初始化状态
dp[].push(,);
now=,pre=;
for(int i=;i<=n;i++)//逐格逐状态枚举转移
{
pre=now,now^=,dp[now].clear();
for(int k=;k<dp[pre].size;k++)//轮廓线行转移
dp[now].push(dp[pre].sta[k]<<inc,dp[pre].sum[k]);
for(int j=;j<=m;j++)
{
pre=now,now^=,dp[now].clear();
for(int k=;k<dp[pre].size;k++)
{
DP(i,j,k);
}
}
}
for(int i=;i<dp[now].size;i++)
if(dp[now].sta[i]==)
return dp[now].sum[i];
return ;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
for(int i=;i<=n;i++)//都是从1开始
scanf("%s",&gp[i][]);
fx=fy=;
for(int i=n;i>&&!fx;i--)//寻找最终的位置
for(int j=m;j>&!fx;j--)
if(gp[i][j]=='.')
fx=i,fy=j;
if(fx==)puts("");
else cout<<solve()<<endl;
}
}

ural 1519 Formula 1的更多相关文章

  1. bzoj 1814 Ural 1519 Formula 1 插头DP

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

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

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

  3. 【BZOJ1814】Ural 1519 Formula 1 插头DP

    [BZOJ1814]Ural 1519 Formula 1 题意:一个 m * n 的棋盘,有的格子存在障碍,求经过所有非障碍格子的哈密顿回路个数.(n,m<=12) 题解:插头DP板子题,刷板 ...

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

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

  5. ural 1519 Formula 1(插头dp)

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

  6. bzoj1814: Ural 1519 Formula 1 动态规划 插头dp

    http://acm.timus.ru/problem.aspx?space=1&num=1519 题目描述 一个 m * n 的棋盘,有的格子存在障碍,求经过所有非障碍格子的哈密顿回路个数. ...

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

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

  8. BZOJ1814: Ural 1519 Formula 1(插头Dp)

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

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

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

随机推荐

  1. Android应用之基本的组件(一)

    请大家伙多多指教: 邮箱:weimingweicom@sina.com 请关注:ailiandeziwei 总的页面: 注意:按钮间方法的改变需要:     android:onClick=" ...

  2. (step6.1.5)hdu 1233(还是畅通工程——最小生成树)

    题目大意:输入一个整数n,表示有n个村庄,在接下来的n*(n-1)/2中,每行有3个整数beigin.end.weight,分别表示路的起始村庄,结束村庄和村庄之间的距离. 求索要修的路的最短距离 解 ...

  3. [JBoss] JNDI与JBossNS

    JNDI的作用 JNDI是 Java 命名与目录接口(Java Naming and Directory Interface). 随着分布式应用的发展,远程访问对象访问成为常用的方法.虽然说通过Soc ...

  4. C#基础 大盘点

      类型转换   tryParse    字符和整形转换   转译符:  /' 单引号      /" 双引号      // 反斜杠        /0 空字符       /a 感叹号( ...

  5. Windows Services的1053错误的解决办法之一:修改注册表允许的响应时间

    Error: 'The service did not respond in a timely fashion' (ServicesPipeTimeout) when attempting when ...

  6. 使用 jackson序列格式化日期

    [1]自定义时间,序列化类 [java] view plaincopy package com.fsti.bm.utils; import java.io.IOException; import ja ...

  7. perl use utf8

    utf8 Perl编译 来启用/禁用 UTF-8(or UTF-EBCDIC) 在源代码里 简洁: use utf8; no utf8; # Convert the internal represen ...

  8. 使用boost中的property_tree实现配置文件

    property_tree是专为配置文件而写,支持xml,ini和json格式文件   ini比较简单,适合简单的配置,通常可能需要保存数组,这时xml是个不错的选择.   使用property_tr ...

  9. hdu 1421 搬寝室 (dp)

    思路分析: dp[i][j] 表示选取到第 i 个   组成了 j 对的最优答案. 当然排序之后 选取相邻两个是更优的. if(i==j*2) dp[i][j] = dp[i-2][j-1] + w[ ...

  10. EEPlat PaaS VS Saleforce force.com

    综述 EEPlatPaaS和Saleforce的Force.com都是元数据驱动应用的解决方式.整体而言,Force.com提供了更上层的解决方式,屏蔽了SQL语句.数据库:EEPlat更加底层,有更 ...