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,一经查实,立即删除!

相关文章

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;而中文简称为“文传协议”。用…

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

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

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

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

MySQL触发器 trigger学习

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

js调试笔记

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

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

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

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;公司及个人机构大…

第一篇:SpringCloud 构建微服务系统之服务注册和发现(consul)

版权声明&#xff1a;本文为博主原创文章&#xff0c;未经博主允许不得转载。 https://blog.csdn.net/u010046908/article/details/85260629 今天我们要学习的是consul在soringcloud中的使用。首先学习consul之前&#xff0c;我们应该看看consul的官网&#xff0c;对它有一个初…

2018 年视频监控企业竞争力分析 海康威视连续七年蝉联全球第一

视频监控是安防行业的核心 近年来&#xff0c;随着我国政府对平安城市、" 雪亮工程 " 以及金融和交通运输等领域的重视&#xff0c;对于安防产品的需求不断提升&#xff0c;安防市场规模也在随之不断扩大。视频监控是整个安防系统最重要的物理基础&#xff0c;视频监…

Ambient occlusion

https://en.wikipedia.org/wiki/Ambient_occlusion https://gamedev.stackexchange.com/questions/23/what-is-ambient-occlusion http://people.mpi-inf.mpg.de/~ritschel/Papers/SSDO.pdf 注解&#xff1a; 论文&#xff08;http://people.mpi-inf.mpg.de/~ritschel/Papers/S…

利用RTL2832u电视棒芯片追踪民航飞机轨迹

我国民航飞机通讯的频率为1090Mhz&#xff0c;而rtl2832u电视棒芯片可以接受的频率范围为24 – 1766 MHz&#xff08;通过改制Q通道可以接收0-30Mhz的短波&#xff09;下面开始介绍利用rtl2832u电视棒芯片获取民航航线 第一步淘宝搜索rtl2832u820T(50块钱就能买到) <ignore_…

预见2019:《2019年中国视频监控产业全景图谱》(附产业布局、政策环境、市场规模、发展趋势)

2019-2024年中国视频监控设备行业市场需求预测与投资战略规划分析报告2019-2024年中国安防行业市场前瞻与投资战略规划分析报告2019-2024年中国智能安防行业市场前瞻与投资战略规划分析报告2019-2024年中国智能家居设备行业市场前瞻与投资策略规划报告2019-2024年中国城市轨道交…

终于有人把EMC基础知识总结如此清晰

传导与辐射 电磁干扰(Electromagnetic Interference)&#xff0c;简称EMI&#xff0c;有传导干扰和辐射干扰两种。传导干扰主要是电子设备产生的干扰信号通过导电介质或公共电源线互相产生干扰&#xff1b;辐射干扰是指电子设备产生的干扰信号通过空间耦合把干扰信号传给另一个…

一个go1.9.x 编译器内联引起的栈信息错乱的问题分析

2019独角兽企业重金招聘Python工程师标准>>> 背景是在写个日志库&#xff0c;日志库有个很重要的功能就是要打印出调用栈&#xff0c;知道具体是哪个文件&#xff0c;哪个函数调用的Info 等。 然后在测试中发现了一种写法&#xff0c;我自己本机测试一直ok&#xff…

Learn Python—表达式、数据类型、流程控制

表达式 在 Python 中&#xff0c;2 2 称为“表达式”&#xff0c;它是语言中最基本的编程结构。表达式包含“值”&#xff08;例如2&#xff09;和“操作符”&#xff08;例如&#xff09;&#xff0c;并且总是可以求值&#xff08;也就是归约&#xff09;为单个值。这意味着在…

Python并发编程之concurrent.futures

2019独角兽企业重金招聘Python工程师标准>>> concurrent.futures模块提供了一个异步执行callables的高级接口。 可以使用ThreadPoolExecutor和ProcessPoolExecutor。 两者都继承了相同的接口&#xff0c;该接口由抽象的Executor类定义。 一个抽象类&#xff0c;提供…

移植opencv3.20到3556AV100

1.移植环境&#xff1a; Ubuntu14.04 arm-hisiv200-linux-opencv3.20 下载地址 2.移植步骤&#xff1a; 1&#xff09;安装cmake-gui 2&#xff09;新建一个opencv目录存放opencv-3.2.0.zip&#xff0c;并解压 击Browse Source选择~/hisi/opencv/opencv-3.2.0 点击Brow…