1519. Formula 1

Time limit: 1.0 second

Memory limit: 64 MB

Background

Regardless of the fact, that Vologda could not get rights to hold the Winter Olympic games of 20**, it is well-known, that the city will conduct one of the Formula 1 events. Surely, for such an important
thing a new race circuit should be built as well as hotels, restaurants, international airport - everything for Formula 1 fans, who will flood the city soon. But when all the hotels and a half of the restaurants were built, it appeared, that at the site for
the future circuit a lot of gophers lived in their holes. Since we like animals very much, ecologists will never allow to build the race circuit over the holes. So now the mayor is sitting sadly in his office and looking at the map of the circuit with all
the holes plotted on it.

Problem

Who will be smart enough to draw a plan of the circuit and keep the city from inevitable disgrace?

Of course, only true professionals - battle-hardened programmers from the first team of local technical
university!.. But our heroes were not looking for easy life and set much more difficult problem: "Certainly, our mayor will be glad, if we find how many ways of building the circuit are there!" - they said.

It should be said, that the circuit in Vologda is going to be rather simple. It will be a rectangleN*M cells in size with a single circuit segment built through each
cell. Each segment should be parallel to one of rectangle's sides, so only right-angled bends may be on the circuit. At the picture below two samples are given for N = M = 4 (gray squares mean gopher holes, and the bold black
line means the race circuit). There are no other ways to build the circuit here.

Input

The first line contains the integer numbers N and M (2 ≤ NM ≤ 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.

Output

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

Samples

input output
4 4
**..
....
....
....
2
4 4
....
....
....
....
6

分析看这(转):http://blog.sina.com.cn/s/blog_51cea4040100gmky.html

依照上面链接分析就非常明白了,情况分清楚了就好写了

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <queue>
#include <algorithm>
#include <map>
#include <cmath>
#include <iomanip>
#define INF 99999999
typedef long long LL;
using namespace std; const int MAX=300000+10;//最多的有效状态
const int N=10+10;
int n,m,size,index;
int mp[N][N],total[2],bit[N],ex,ey;//ex,ey记录最后一个非限制点,total记录有多少状态
int head[MAX],Next[MAX],Hash[MAX];//Hash用哈希查询状态,才用邻接表查询
//对于第i,j格仅仅须要用到第i,j-1格到达,所以才用滚动数组节省内存
LL dp[2][MAX],state[2][MAX],sum;//state记录对应状态,dp记录对应状态可到达的数量 void Init(){
memset(mp,0,sizeof mp);
sum=size=index=0;
total[index]=1;
state[index][1]=0;//初始化仅仅有一种可到达状态:没有不论什么插头
dp[index][1]=1;
} void HashCalState(LL s,LL num){
int pos=s%MAX;
for(int i=head[pos];i != -1;i=Next[i]){
if(state[index][Hash[i]] == s){
dp[index][Hash[i]]+=num;
return;
}
}
++total[index];
state[index][total[index]]=s;
dp[index][total[index]]=num;
//头插法
Hash[size]=total[index];
Next[size]=head[pos];
head[pos]=size++;
} void DP(){//才用4进制进行DP,x*4^y=x*2^(2*y)
for(int i=1;i<=n;++i){
for(int k=1;k<=total[index];++k)state[index][k]<<=2;//由上移一行到达这一行(i,0格)在上一行的0号插头前面再加一个插头,去掉最后一个插头(最后一个插头肯定为0)
for(int j=1;j<=m;++j){//求由i,j-1到达i,j的状态以及状态数
memset(head,-1,sizeof head);
size=0;
index=index^1;
total[index]=0;
for(int k=1;k<=total[index^1];++k){//枚举上一格的状态,用来到达i,j某个状态
LL s=state[index^1][k];//取状态
LL num=dp[index^1][k];//取到达对应状态个数
int p=(s>>bit[j-1])%4;//取第j位
int q=(s>>bit[j])%4;//取第j+1位
if(!mp[i][j]){//i,j有限制不能通过,必须绕过
if(p+q == 0)HashCalState(s,num);//仅仅有p=q=0才干到达p'=q'=0的状态,才用哈希计算到达的状态以及个数
}else if(p+q == 0){//i,j无限制则必须有两个插头通过(一进一出)
if(!mp[i+1][j] || !mp[i][j+1])continue;
s=s+(1<<bit[j-1])+2*(1<<bit[j]);//创建新的连通块(添加第j,j+1个插头)
HashCalState(s,num);
}else if(!p && q){//p无插头,q有插头,则新状态须要添加一个插头
if(mp[i][j+1])HashCalState(s,num);//状态不变,连通块不变
if(mp[i+1][j]){
s=s+q*(1<<bit[j-1])-q*(1<<bit[j]);
HashCalState(s,num);
}
}else if(p && !q){//同上
if(mp[i+1][j])HashCalState(s,num);
if(mp[i][j+1]){
s=s-p*(1<<bit[j-1])+p*(1<<bit[j]);
HashCalState(s,num);
}
}else if(p+q == 2){//p=q=1,合并连通块
int b=1;
for(int t=j+1;t<=m;++t){//寻找近期的匹配的括号
int v=(s>>bit[t])%4;
if(v == 1)++b;
if(v == 2)--b;
if(b == 0){
s=s+(1<<bit[t])-2*(1<<bit[t]);//将右括号变为左括号
break;
}
}
s=s-(1<<bit[j-1])-(1<<bit[j]);
HashCalState(s,num);
}else if(p+q == 4){//p=q=2,同上
int b=1;
for(int t=j-2;t>=0;--t){//寻找近期的匹配括号
int v=(s>>bit[t])%4;
if(v == 2)++b;
if(v == 1)--b;
if(b == 0){
s=s-(1<<bit[t])+2*(1<<bit[t]);//将左括号变为右括号
break;
}
}
s=s-2*(1<<bit[j-1])-2*(1<<bit[j]);
HashCalState(s,num);
}else if(p == 1 && q == 2){//合并连通块,仅仅有最后一格的时候才连成整个回路
if(i == ex && j == ey)sum+=num;
}else if(p == 2 && q == 1){
s=s-2*(1<<bit[j-1])-(1<<bit[j]);
HashCalState(s,num);
}
}
}
}
} int main(){
char ch;
for(int i=0;i<N;++i)bit[i]=i<<1;//求4进制的某位用2进制求须要右移的位数*2
while(~scanf("%d%d",&n,&m)){
Init();
for(int i=1;i<=n;++i){
getchar();
for(int j=1;j<=m;++j){
scanf("%c",&ch);
mp[i][j]=(ch == '.');
if(ch == '.')ex=i,ey=j;
}
}
DP();//插头DP
printf("%lld\n",sum);
}
return 0;
}
/*
12 12
............
............
............
............
............
............
............
............
............
............
............
............
9 10
..........
..........
..........
..........
..........
..........
..........
..........
..........
*/

版权声明:本文博客原创文章,博客,未经同意,不得转载。

ural1519插头DP的更多相关文章

  1. URAL1519 Formula 1 【插头dp】

    题目链接 URAL1519 题解 看题型显然插头\(dp\) 考虑如何设计状态 有这样一个方案 当我们决策到某个位置 轮廓线长这样 你会发现插头一定是相互匹配的 所以我们实际上可以把状态用括号序列表示 ...

  2. URAL1519 Formula 1 —— 插头DP

    题目链接:https://vjudge.net/problem/URAL-1519 1519. Formula 1 Time limit: 1.0 secondMemory limit: 64 MB ...

  3. [URAL1519] Formula 1 [插头dp入门]

    题面: 传送门 思路: 插头dp基础教程 先理解一下题意:实际上就是要你求这个棋盘中的哈密顿回路个数,障碍不能走 看到这个数据范围,还有回路处理,就想到使用插头dp来做了 观察一下发现,这道题因为都是 ...

  4. 模板:插头dp

    前言: 严格来讲有关dp的都不应该叫做模板,因为dp太活了,但是一是为了整理插头dp的知识,二是插头dp有良好的套路性,所以姑且还叫做模板吧. 这里先推荐一波CDQ的论文和这篇博客http://www ...

  5. 省选算法学习-插头dp

    插头dp?你说的是这个吗? 好吧显然不是...... 所谓插头dp,实际上是“基于连通性的状态压缩dp”的简称,最先出现在cdq的论文里面 本篇博客致力于通过几道小小的例题(大部分都比较浅显)来介绍一 ...

  6. [HNOI2007][bzoj1187] 神奇游乐园 [插头dp]

    题面: 传送门 给定一个四联通棋盘图,每个格子有权值,求一条总权值最大的回路 思路: 插头dp基础教程 棋盘? 回路? n,m<=10? 当然是插头dp啦~\(≧▽≦)/~ 然后发现这道题并不是 ...

  7. ural 1519 fomular 1 既插头DP学习笔记

    直接看CDQ在2008年的论文吧. 个人认为她的论文有两个不明确的地方, 这里补充一下: 首先是轮廓的概念. 我们在进行插头DP时, 是从上往下, 从左往右逐个格子进行的, 已经处理的格子与未经处理的 ...

  8. 插头dp

    插头dp 感受: 我觉得重点是理解,算法并不是直接想出怎样由一种方案变成另一种方案.而是方案本来就在那里,我们只是枚举状态统计了答案. 看看cdq的讲义什么的,一开始可能觉得状态很多,但其实灰常简单 ...

  9. HDU 4113 Construct the Great Wall(插头dp)

    好久没做插头dp的样子,一开始以为这题是插头,状压,插头,状压,插头,状压,插头,状压,无限对又错. 昨天看到的这题. 百度之后发现没有人发题解,hust也没,hdu也没discuss...在acm- ...

随机推荐

  1. NET MVC权限验证

    ASP.NET MVC权限验证 封装类 写该权限类主要目地 为了让权限配置更加的灵活,可以根据SQL.json.或者XML的方式来动态进行页面的访问控制,以及没有权限的相关跳转. 使用步骤 1.要建一 ...

  2. 《Programming Hive》读书笔记(一)Hadoop和hive环境搭建

    <Programming Hive>读书笔记(一)Hadoop和Hive环境搭建             先把主要的技术和工具学好,才干更高效地思考和工作.   Chapter 1.Int ...

  3. 使用eclips发展java当闪回的问题

    近期開始android的开发学习.当然要先从java入手了.我选择eclips作为开发的IDE,在測试java代码例子时,假设我的代码是能够出现系统自己主动代码补齐时eclips就会立马闪退. 刚開始 ...

  4. 《Effective C++》:规定44-规定45

    规定44分离的不依赖参数代码templates 条款45运用成员函数模板接受全部兼容类型 Templates和泛型编程 条款44:将与參数无关的代码抽离templates Templates能够节省时 ...

  5. win8 iis7/iis8 安装、卸载、设置方法

    原文:win8 iis7/iis8 安装.卸载.设置方法 一.安装 自从升级到Win8之后,之前使用已经趋于熟悉的iis7.0被取而代之的是iis8.0,那么安装和获取方法也就产生的略微的变化,为了避 ...

  6. Jplayer小样

    最近应公司要求需要一个MP3播放的插件,网上找了很多插件,看来看去还是jPlayer用着最舒服也最容易扩展.所以就找了个资料研究了下,简单做了个小DEMO.支持实时控制列表,常见的播放器功能. jPl ...

  7. HDU 4085 Steiner树模板称号

    Dig The Wells Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) To ...

  8. swift UI特殊培训38 与滚动码ScrollView

    有时我们适合页面的全部内容,我们需要使用ScrollView,额外的内容打通滚动. 什么样的宽度和高度首先,定义,健身器材轻松. let pageWidth = 320 let pageHeight ...

  9. Android fragment onActivityResult 不起作用

    fragment 跳转至Acivity后,fragment里面的onActivityResult 被被调用 试过非常多办法,最后getactivity().startactivityforresult ...

  10. hdu 4975 最大流问题解决队伍和矩阵,利用矩阵dp优化

    //刚開始乱搞. //网络流求解,假设最大流=全部元素的和则有解:利用残留网络推断是否唯一, //方法有两种,第一种是深搜看看是否存在正边权的环.见上一篇4888 //至少四个点构成的环,另外一种是用 ...