Tirp(状压DP)
Description
有一个N*N的迷宫,其中有一些宝藏,现在,小A要从入口(1,1)出发,到达出口(N,N),每次,小A只能从当前的格子走到上下左右四个格子,为了不空手而归,小A决定要拿到所以的宝藏。请问,他最少要走多少步,才能拿到宝藏?
Input Format
第一行:一个整数N,表示迷宫的大小。
第二到第(N+1)行,每行有N个字符,代表迷宫的情况,其中‘0’代表路径,‘1’代表墙面,‘2’代表宝藏
Output Format
一行,一个整数,表示最少步数,或者输出No Solution,表示无法取到所以宝藏
Sample Input
3
011
020
110
Sample Output
4
Hint
100%,N<=30,宝藏个数<=13
Solution
首先,宝藏个数<=13,自然想到状压DP, 用二进制数表示状态,‘1’代表这个宝藏去过了,‘0’代表没有,
那么可以用F[i][S]表示状态为S时,且位于第i个宝藏的最短步数。
那么容易得到方程F[i][S]=min{F[k][S^(1<<(i-1))]+dis[i][k]},其中1<=k<=宝藏个数,dis[i][k]表示第i个宝藏到第k个宝藏的最少步数
那么最后答案就为min{F[i][(1<<m)-1]+toEnd[i]},其中toEnd[i]表示从宝藏i到点(N ,N )的最少步数.
dis数组和toEnd数组可以用bfs预处理得到,细节也不少,当无法到达终点或有至少一个宝藏拿不到就是无解的情况,而且要特判没有宝藏时直接输出到终点的距离
当初挂了好几次,主要有以下几点原因:
- 记忆化时tmp忘记初始化为INF,导致答案都为-1
- 没有考虑没有宝藏的情况(m==0)
- 没有考虑到不了终点的情况
- 方程原来写成转移到DP(i, S ^ (1 << (i - 1)),应该是'(p-1)'
- 读入时临时字符串数组开小,导致RE
Code
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
const int dx[4] = {0, 0, 1, -1};
const int dy[4] = {1, -1, 0, 0};
struct point {
point(int a, int b) {x = a, y = b;}
int x, y;
};
struct info {
int x, y;
} bag[32];
int n, a[32][32], m, f[32][1 << 16], dis[32][32], toEnd[32], toBag[32];
int d[32][32];
bool vis[32][32];
queue<point> q;
bool flag;
void bfs(int k, int sx, int sy) {
memset(vis, 0, sizeof(vis));
memset(d, -1, sizeof(d));
d[sx][sy] = 0;
while (!q.empty()) q.pop();
q.push(point(sx, sy));
vis[sx][sy] = 1;
while (!q.empty()) {
point u = q.front();
int x = u.x, y = u.y;
q.pop();
for (int i = 0; i < 4; ++i) {
int nx = x + dx[i], ny = y + dy[i];
if (nx <= 0 || ny <= 0 || nx > n || ny > n || vis[nx][ny] || a[nx][ny]) continue;
vis[nx][ny] = 1;
d[nx][ny] = d[x][y] + 1;
q.push(point(nx, ny));
}
}
for (int i = k + 1; i <= m; ++i) {
int x = bag[i].x, y = bag[i].y;
if (d[x][y] == -1) {
if (k == 0) flag = 1;
continue;
}
if (k == 0) toBag[i] = d[x][y];
else dis[k][i] = dis[i][k] = d[x][y];
}
if (d[n][n] == -1) flag = 1;
toEnd[k] = d[n][n];
}
int DP(int p, int S) {
int &tmp = f[p][S];
if (tmp != -1) return tmp;
tmp = (int)1e9;
for (int i = 1; i <= m; ++i) {
if (i == p) continue;
if (!((1 << (i - 1))&S)) continue;
tmp = min(tmp, DP(i, S ^ (1 << (p - 1))) + dis[i][p]);
}
return tmp;
}
int main() {
scanf("%d", &n);
memset(dis, 0x3f, sizeof(dis));
for (int i = 1; i <= n; ++i) {
char s[32];
scanf("%s\n", s);
for (int j = 0; j < n; ++j) {
a[i][j + 1] = s[j] - '0';
if (a[i][j + 1] == 2) {
a[i][j + 1] = 0;
bag[++m].x = i;
bag[m].y = j + 1;
}
}
}
bfs(0, 1, 1);
if (flag) {
printf("No Solution\n");
return 0;
}
for (int i = 1; i <= m; ++i)
bfs(i, bag[i].x, bag[i].y);
int Ans = (int)1e9;
memset(f, -1, sizeof(f));
for (int i = 1; i <= m; ++i)
f[i][1 << (i - 1)] = toBag[i];
for (int i = 1; i <= m; ++i)
Ans = min(Ans, DP(i, (1 << m) - 1) + toEnd[i]);
if (m == 0) Ans = toEnd[0];
printf("%d\n", Ans);
return 0;
}
Tirp(状压DP)的更多相关文章
- BZOJ 1087: [SCOI2005]互不侵犯King [状压DP]
1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 3336 Solved: 1936[Submit][ ...
- nefu1109 游戏争霸赛(状压dp)
题目链接:http://acm.nefu.edu.cn/JudgeOnline/problemShow.php?problem_id=1109 //我们校赛的一个题,状压dp,还在的人用1表示,被淘汰 ...
- poj3311 TSP经典状压dp(Traveling Saleman Problem)
题目链接:http://poj.org/problem?id=3311 题意:一个人到一些地方送披萨,要求找到一条路径能够遍历每一个城市后返回出发点,并且路径距离最短.最后输出最短距离即可.注意:每一 ...
- [NOIP2016]愤怒的小鸟 D2 T3 状压DP
[NOIP2016]愤怒的小鸟 D2 T3 Description Kiana最近沉迷于一款神奇的游戏无法自拔. 简单来说,这款游戏是在一个平面上进行的. 有一架弹弓位于(0,0)处,每次Kiana可 ...
- 【BZOJ2073】[POI2004]PRZ 状压DP
[BZOJ2073][POI2004]PRZ Description 一只队伍在爬山时碰到了雪崩,他们在逃跑时遇到了一座桥,他们要尽快的过桥. 桥已经很旧了, 所以它不能承受太重的东西. 任何时候队伍 ...
- bzoj3380: [Usaco2004 Open]Cave Cows 1 洞穴里的牛之一(spfa+状压DP)
数据最多14个有宝藏的地方,所以可以想到用状压dp 可以先预处理出每个i到j的路径中最小权值的最大值dis[i][j] 本来想用Floyd写,无奈太弱调不出来..后来改用spfa 然后进行dp,这基本 ...
- HDU 1074 Doing Homework (状压dp)
题意:给你N(<=15)个作业,每个作业有最晚提交时间与需要做的时间,每次只能做一个作业,每个作业超出最晚提交时间一天扣一分 求出扣的最小分数,并输出做作业的顺序.如果有多个最小分数一样的话,则 ...
- 【BZOJ1688】[Usaco2005 Open]Disease Manangement 疾病管理 状压DP
[BZOJ1688][Usaco2005 Open]Disease Manangement 疾病管理 Description Alas! A set of D (1 <= D <= 15) ...
- 【BZOJ1725】[Usaco2006 Nov]Corn Fields牧场的安排 状压DP
[BZOJ1725][Usaco2006 Nov]Corn Fields牧场的安排 Description Farmer John新买了一块长方形的牧场,这块牧场被划分成M列N行(1<=M< ...
随机推荐
- 201521123067《Java程序设计》第1周学习总结
1.本周学习总结 在本周的java学习中,我知道了java的发展历程,JDK和JRE以及JVM的区别与联系,并学习了如何安装Eclipse和搭建java的环境,编写出了第一个java程序,明白了jav ...
- Hyperledger Fabric 1.0 从零开始(二)——环境构建(公网)
1:环境构建 在本文中用到的宿主机环境是Centos ,版本为Centos.x86_647.2,通过Docker 容器来运行Fabric的节点,版本为v1.0.因此,启动Fabric网络中的节点需要先 ...
- Linux第一篇【介绍、安装Ubuntu、基本目录结构】
Linux介绍 Linux:不管是不是我们这些学编程的都肯定会听说过这么一个系统,一般地,我们在PC端都是用Windows操作系统,那我们学习Linux操作系统有什么用呢??? 由于我们的JAVAEE ...
- SSH第一篇【整合SSH步骤、OpenSessionInView】
前言 到目前为止,Struts2.Hibernate.Spring框架都过了一遍了.也写过了Spring怎么与Struts2整合,Spring与Hibernate整合-本博文主要讲解SSH的整合 整合 ...
- 接口测试入门(3)--使用httpClient进行登录用例操作/set-cookies验证/ List<NameValuePair>设置post参数/json解析
(最近学的都是很基础的接口测试,都是基于UI界面可见的接口,就是发请求,接收响应,分析返回的结果,校验,对共通模块进行封装,仅此而已,其实做自动化的思路基本都是如此,UI也是.) 现在开始用httpC ...
- mybatis 自动生成代码(mybatis generator)
pom.xml 文件配置 引入 mybatis generator <properties> <mysql.connector.version>5.1.44</mysql ...
- 再起航,我的学习笔记之JavaScript设计模式25(迭代器模式)
迭代器模式 概念介绍 迭代器模式(Iterator): 在不暴露对象内部结构的同时,可以顺序地访问聚合对象内部的元素. 迭代器 程序中的循环是一种利器,循环语句也使我们程序开发更简洁高效,但是有时一遍 ...
- 翻译 | Thingking in Redux(如果你只了解MVC)
作者:珂珂(沪江前端开发工程师) 本文原创,转载请注明作者及出处. 原文地址:https://hackernoon.com/thinking-in-redux-when-all-youve-known ...
- Maven(六)之依赖管理
前面讲了maven一些关于Maven的简单知识,今天我给大家分享一些Maven的依赖管理.我相信用过maven的人都知道,它很重要的功能就是通过依赖来添加jar包. 让我们领略一下Maven是怎么管理 ...
- 第6章 Overlapped I/O, 在你身后变戏法 ---1
这一章描述如何使用 overlapped I/O(也就是 asynchronous I/O).某些时候 overlapped I/O 可以取代多线程的功用.然而,overlapped I/O 加上co ...