URAL1519 Formula 1 —— 插头DP

题目链接:https://vjudge.net/problem/URAL-1519

 

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 rectangle N*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.
Problem illustration

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. There are at least 4 cells without gopher holes.

Output

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

Samples

inputoutput
4 4
**..
....
....
....
2
4 4
....
....
....
....
6
Problem Author: Nikita Rybak, Ilya Grebnov, Dmitry Kovalioff
Problem Source: Timus Top Coders: Third Challenge
Tags: none  (hide tags for unsolved problems)

 

 

题意:

用一个回路去走完所有的空格,问有多少种情况?

 

题解:

1.学习插头DP的必经之路:《基于连通性状态压缩的动态规划问题》

2.HDU1693 Eat the Trees 这题的加强版。

3.相对于HDU1693,由于此题限制了只能用一个回路,所以在处理的时候,需要记录轮廓线上,每个插头分别属于哪个连通分量的,以此避免形成多个回路。

4.由于m<=12,故连通分量最多为12/2 = 6个,再加上没有插头的情况,所以轮廓线上每个位置的状态共有7种,为了加快速度,我们采用8进制对其进行压缩。

5.对于一条轮廓线,最多有:8^(12+1)种状态,所以直接用数组进行存储或者直接枚举所以状态是不可行的。但我们知道其中有许多状态是无效的,所以我们采用哈希表来存在有效状态,即能解决空间有限的问题,还能减少直接枚举所需要的时间花费。

 

 

代码如下:

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <vector>
  6 #include <cmath>
  7 #include <queue>
  8 #include <stack>
  9 #include <map>
 10 #include <string>
 11 #include <set>
 12 using namespace std;
 13 typedef long long LL;
 14 const int INF = 2e9;
 15 const LL LNF = 9e18;
 16 const int MOD = 1e9+7;
 17 const int MAXN = 1e5;
 18 const int HASH = 1e4;
 19 
 20 int n, m, last_x, last_y;
 21 bool maze[13][13];
 22 
 23 struct  //注意哈希表的大小
 24 {
 25     int size, head[HASH], next[MAXN];
 26     LL state[MAXN], sum[MAXN];
 27 
 28     void init()
 29     {
 30         size = 0;
 31         memset(head, -1, sizeof(head));
 32     }
 33 
 34     void insert(LL status, LL Sum)
 35     {
 36         int u = status%HASH;
 37         for(int i = head[u]; i!=-1; i = next[i])
 38         {
 39             if(state[i]==status)
 40             {
 41                 sum[i] += Sum;
 42                 return;
 43             }
 44         }
 45         state[size] = status;   //头插法
 46         sum[size] = Sum;
 47         next[size] = head[u];
 48         head[u] = size++;
 49     }
 50 
 51 }Hash_map[2];
 52 
 53 struct
 54 {
 55     int code[13];   //用于记录轮廓线上每个位置的插头状态
 56     LL encode(int m)    //编码:把轮廓线上的信息压缩到一个longlong类型中
 57     {
 58         LL status = 0;
 59         int id[13], cnt = 0;
 60         memset(id, -1, sizeof(id));
 61         id[0] = 0;
 62         for(int i = m; i>=0; i--)   //从高位到低位。为每个连通块重新编号,采用最小表示法。
 63         {
 64             if(id[code[i]]==-1) id[code[i]] = ++cnt;
 65             code[i] = id[code[i]];
 66             status <<= 3;   //编码
 67             status += code[i];
 68         }
 69         return status;
 70     }
 71 
 72     void decode(int m, LL status)  //解码:将longlong类型中轮廓线上的信息解码到数组中
 73     {
 74         memset(code, 0, sizeof(code));
 75         for(int i = 0; i<=m; i++)   //从低位到高位
 76         {
 77             code[i] = status&7;
 78             status >>= 3;
 79         }
 80     }
 81 
 82     void shift(int m)   //左移:在每次转行的时候都需要执行。
 83     {
 84         for(int i = m-1; i>=0; i--)
 85             code[i+1] = code[i];
 86         code[0] = 0;
 87     }
 88 
 89 }Line;
 90 
 91 void transfer_blank(int i, int j, int cur)
 92 {
 93     for(int k = 0; k<Hash_map[cur].size; k++)   //枚举上一个格子所有合法的状态
 94     {
 95         LL status = Hash_map[cur].state[k]; //得到状态
 96         LL Sum = Hash_map[cur].sum[k];      //得到数量
 97         Line.decode(m, status);             //对状态进行解码
 98         int up = Line.code[j];         //得到上插头
 99         int left = Line.code[j-1];     //得到下插头
100 
101         if(!up && !left)        //没有上、左插头,新建分量
102         {
103             if(maze[i+1][j] && maze[i][j+1])    //如果新建的两个插头所指向的两个格子可行,新建的分量才合法
104             {
105                 Line.code[j] = Line.code[j-1] = 6;  //为新的分量编号,最大的状态才为6
106                 Hash_map[cur^1].insert(Line.encode(m), Sum);
107             }
108         }
109         else if( (left&&!up) || (!left&&up) )   //仅有其中一个插头,延续分量
110         {
111             int line = left?left:up;    //记录是哪一个插头
112             if(maze[i][j+1])    //往右延伸
113             {
114                 Line.code[j-1] = 0;
115                 Line.code[j] = line;
116                 Hash_map[cur^1].insert(Line.encode(m), Sum);
117             }
118             if(maze[i+1][j])        //往下延伸
119             {
120                 Line.code[j-1] = line;
121                 Line.code[j] = 0;
122                 if(j==m) Line.shift(m);
123                 Hash_map[cur^1].insert(Line.encode(m), Sum);
124             }
125         }
126         else    //上、左插头都存在,尝试合并。
127         {
128             if(up!=left)    //如果两个插头属于两个联通分量,那么就合并
129             {
130                 Line.code[j] = Line.code[j-1] = 0;
131                 for(int t = 0; t<=m; t++)   //随便选一个编号最为他们合并后分量的编号
132                     if(Line.code[t]==up)
133                         Line.code[t] = left;
134                 if(j==m) Line.shift(m);
135                 Hash_map[cur^1].insert(Line.encode(m), Sum);
136             }
137             else if(i==last_x && j==last_y) //若两插头同属一个分量,则只能在最后的可行格中合并,否则会出现多个联通分量
138             {
139                 Line.code[j] = Line.code[j-1] = 0;
140                 if(j==m) Line.shift(m);
141                 Hash_map[cur^1].insert(Line.encode(m), Sum);
142             }
143         }
144     }
145 }
146 
147 void transfer_block(int i, int j, int cur)
148 {
149     for(int k = 0; k<Hash_map[cur].size; k++)
150     {
151         LL status = Hash_map[cur].state[k]; //得到状态
152         LL Sum = Hash_map[cur].sum[k];      //得到数量
153         Line.decode(m, status);
154         Line.code[j] = Line.code[j-1] = 0;
155         if(j==m) Line.shift(m);
156         Hash_map[cur^1].insert(Line.encode(m), Sum);
157     }
158 }
159 
160 int main()
161 {
162     char s[15];
163     while(scanf("%d%d", &n, &m)!=EOF)
164     {
165         memset(maze, false, sizeof(maze));
166         for(int i = 1; i<=n; i++)
167         {
168             scanf("%s", s+1);
169             for(int j = 1; j<=m; j++)
170             {
171                 if(s[j]=='.')
172                 {
173                     maze[i][j] = true;
174                     last_x = i;         //记录最后一个可行格
175                     last_y = j;
176                 }
177             }
178         }
179 
180         int cur = 0;
181         Hash_map[cur].init();   //初始化
182         Hash_map[cur].insert(0, 1); //插入初始状态
183         for(int i = 1; i<=n; i++)
184         for(int j = 1; j<=m; j++)
185         {
186             Hash_map[cur^1].init();
187             if(maze[i][j])
188                 transfer_blank(i, j, cur);
189             else
190                 transfer_block(i, j ,cur);
191             cur ^= 1;
192         }
193 
194         LL last_status = 0; //最后的轮廓线就是最后一行,且每个位置都没有插头
195         LL ans = Hash_map[cur].size?Hash_map[cur].sum[last_status]:0;
196         printf("%I64d\n", ans);
197     }
198 }
View Code

 

转载于:https://www.cnblogs.com/DOLFAMINGO/p/8004121.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/252738.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

电子透雾与光学透雾监控摄像机区别

当你在疯狂购物时也目前已知的透雾算法大致可以分为两大类&#xff1a;一种是非模型的图像增强方法&#xff0c;通过增强图像的对比度&#xff0c;满足主观视觉的要求来达到清晰化的目的&#xff1b;另一种是基于模型的图像复原方法&#xff0c;它考查图像退化的原因&#xff0…

sshfs的挂载与卸载

在CentOS中 sshfs的使用依赖EPEL(只安装sshfs不会出错&#xff0c;但是却无法使用) 挂载 安装EPEL rpm -i https://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm 如果这个链接失效&#xff0c;可访问官网http://fedoraproject.org/wiki/EPEL 安装sshfs…

2018年中国视频监控行业发展空间巨大 AI技术赋能发展乃是未来必然趋势

https://bg.qianzhan.com/report/detail/459/190131-c2610ca0.html2019-2024年中国视频监控设备行业市场需求预测与投资战略规划分析报告2019-2024年中国安防行业市场前瞻与投资战略规划分析报告2019-2024年中国智能安防行业市场前瞻与投资战略规划分析报告2019-2024年中国智能…

FTP下载文件

今天公司有需求&#xff0c;需要从远程FTP服务器上下载文件到本地代码。然后看了一下&#xff0c;顺便做个记录 什么是FTP呢&#xff1f; 详细百度百科 FTP 是File Transfer Protocol&#xff08;文件传输协议&#xff09;的英文简称&#xff0c;而中文简称为“文传协议”。用…

tomcat启动报错The JRE could not be found.Edit the server and change the JRE location

解决&#xff1a; 在Windows->Preferences->Server->Runtime Environments 选择Tomcat->Edit&#xff0c;在jre中选择相应的jdk版本&#xff0c;完事。转载于:https://www.cnblogs.com/Alwaysbecoding/p/10172752.html

tortoisegit推送ssh-key需要输入用户信息

修改了测试代码&#xff0c;却在提交代码时候又跳出来请输入用户名和密码, 后来发现&#xff0c;github push有两种方式&#xff0c;ssh方式和https方式。而https方式是不同的&#xff0c;具体来说&#xff0c;就是url信息的不同&#xff0c;实际的验证机制也是不同的。当建立了…

2018年中国视频监控行业现状及行业发展趋势分析预测【图】

一、中国视频监控行业现状 中国 2013-2018 年模拟标清视频监控摄像机和模拟高清视频监控摄像机的复合增长率分别为-15.2%、 29.6%。 模拟标清视频监控摄像机需求量不断下降&#xff0c; 预计 2018 年同比下降 13%&#xff0c; 将下降到 0.38 亿台。 模拟高清视频监控摄像机需求…

周总结02

周一周二周三周四周五周六 所花时间 &#xff5b;包括上课&#xff5d; 16&#xff1a;50- 17&#xff1a;50 8&#xff1a;00-9&#xff1a;50 15&#xff1a;00-16&#xff1a;00 15&#xff1a;00- 16&#xff1a;30 0 10&#xff1a;10- 12&#xff1a;00 8&#xff…

C#中控制线程池的执行顺序

在使用线程池时&#xff0c;当用线程池执行多个任务时&#xff0c;由于执行的任务时间过长&#xff0c;会导制两个任务互相执行&#xff0c;如果两个任务具有一定的操作顺序&#xff0c;可能会导制不同的操作结果&#xff0c;这时&#xff0c;就要将线程池按顺序操作。下面先给…

MySQL触发器 trigger学习

触发器&#xff1a;一类特殊的事物。可监视某种数据操作&#xff0c;并触发相关操作&#xff08;insert/update/delete&#xff09;。表中的某些数据改变&#xff0c;希望同一时候能够引起其他相关数据改变的需求。 作用&#xff1a;变化自己主动完毕某些语句查询&#xff0c;加…

如何分析企业未来发展趋势——以海康威视为例

财务分析主要基于历史数据&#xff0c;但投资还需要看到企业未来的发展。 在前一篇的财务分析的文章中已经提到过&#xff1a;财务分析只是手段&#xff0c;最终还是要从中发现企业的竞争优势以及行业的发展趋势&#xff0c;并以此为基础&#xff0c;分析企业未来的竞争优势及…

java与C++的区别

java与C的区别 来源 https://www.cnblogs.com/Allen-rg/p/6692043.html “作为一名C程序员&#xff0c;我们早已掌握了面向对象程序设计的基本概念&#xff0c;而且Java的语法无疑是非常熟悉的。事实上&#xff0c;Java本来就是从C衍生出来的。”  然而&#xff0c;C和Java之…

js调试笔记

js调试方法很多&#xff0c;今天总结一下最实用的的断点方法: debugger断点 这个很常见&#xff0c;但许多人不知道其实可以添加条件判断 if(something){debugger;} source断点 这个最为常见&#xff0c;不做过多解释&#xff0c;具体说一下几个重要图标: 恢复脚本执行至下一个…

JAVA Spring 事物 ( 已转账为例 ) 基于 AOP 注解

<一> 配置为文件 <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.springframework.org/schema/beans"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xmlns:context"http://www.springf…

全球视频监控设备市场规模分析

权威电子行业研究机构IHS Research发布《中国CCTV与视频监控设备市场研究报告》显示&#xff0c;2014年全球视频监控设备市场143亿美元&#xff0c;同比增长14.2%。欧洲、美洲、亚洲都增长低于预期;中国增长高于预期&#xff0c;市场总量达57.1亿美元;美国市场虽然出货量在增加…

vue 新窗口打开外链接

背景&#xff1a;vue-router 打开外链接 如果使用 a 标签&#xff0c;会默认加上根路由&#xff0c;导致跳转失效。那么如何让 a 标签点击跳转到新窗口&#xff1f;解决方法&#xff1a;html 代码<a class"a-style" click"linkDownload(https://www.baidu.co…

EasyWeChat微信开放平台第三方平台接入

目录实例化微信服务器推送事件预授权获取预授权 Code获取预授权 URLAPI 列表使用授权码换取公众号的接口调用凭据和授权信息获取授权方的公众号帐号基本信息获取授权方的选项设置信息设置授权方的选项信息调用授权方 API实例化<?phpuse EasyWeChat\Foundation\Application;…

201521145048《Java程序设计》第11周学习总结

1. 本周学习总结 1.1 以你喜欢的方式&#xff08;思维导图或其他&#xff09;归纳总结多线程相关内容。 2. 书面作业 本次PTA作业题集多线程 Q1.互斥访问与同步访问 完成题集4-4(互斥访问)与4-5(同步访问) 1.1 除了使用synchronized修饰方法实现互斥同步访问&#xff0c;还有什…

修改chrome记住密码后自动填充表单的背景

2019独角兽企业重金招聘Python工程师标准>>> input:-webkit-autofill, textarea:-webkit-autofill, select:-webkit-autofill {background-color: rgb(250, 255, 189); /* #FAFFBD; */background-image: none;color: rgb(0, 0, 0); } 转载于:https://my.oschina.net…

2018年我国视频监控市场趋势:智能视频分析进入规模化

在安防领域中&#xff0c;视频监控无疑是不可缺少的一环。我国是全球视频安防行业增速最快的国家之一&#xff0c;近年来我国的视频监控市场经历了持续强劲的发展。我国视频监控市场的高速增长反映了对个人安全及财产保护的担忧增加。为解决该担忧&#xff0c;公司及个人机构大…