题意:一张图,F是起点,Y是必须要到的点,D不能走,G可以充电。可以往四个方向走,每走一步花费一个电,走到G可以选择充满电或者不充,每个G只能充一次。问你走遍Y的最小初始点亮。number(G) + number(Y) <= 15

思路:显然Y和G都只要用一次就行,那么状压YG状态。然后BFS出任意YG两点最短路,状压DP。用&判断最终结果是不是当前状态的子集。

代码:

#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include <iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 15;
const int M = maxn * 30;
const ull seed = 131;
const int INF = 0x3f3f3f3f;
const int MOD = 1e4 + 7;
int dp[1 << maxn][maxn];
char mp[maxn + 10][maxn + 10];
int n, m, sx, sy;
int cnt;
int id[maxn * maxn + 20];
int bettery[maxn * maxn + 20];
int getid(int x, int y){
return id[x * m + y];
}
struct Node{
int x, y, step;
};
int dis[maxn * maxn + 10][maxn * maxn + 10];
int vis[maxn + 5][maxn + 5];
int to[4][2] = {0, 1, 0, -1, 1, 0, -1, 0};
void bfs(int x, int y){
memset(vis, 0, sizeof(vis));
Node a, b;
queue<Node> q;
while(!q.empty()) q.pop();
vis[x][y] = 1;
a.x = x, a.y = y, a.step = 0;
q.push(a);
while(!q.empty()){
a = q.front();
q.pop();
if(mp[a.x][a.y] != 'D' && mp[a.x][a.y] != 'S') dis[getid(x, y)][getid(a.x, a.y)] = a.step;
for(int i = 0; i < 4; i++){
b.x = a.x + to[i][0];
b.y = a.y + to[i][1];
if(b.x < 0 || b.y < 0 || b.x >= n || b.y >= m) continue;
if(vis[b.x][b.y]) continue;
if(mp[b.x][b.y] == 'D') continue;
vis[b.x][b.y] = 1;
b.step = a.step + 1;
q.push(b);
}
}
} int Fin;
bool check(int st){
memset(dp, -1, sizeof(dp));
for(int i = 0; i < cnt; i++){
if(dis[cnt][i] <= st){
if(bettery[i]) dp[1 << i][i] = st;
else dp[1 << i][i] = st - dis[cnt][i];
}
} for(int i = 0; i < (1 << cnt); i++){
for(int j = 0; j < cnt; j++){
if(dp[i][j] == -1) continue;
if(!((1 << j) & i)) continue;
if((i & Fin) == Fin) return true;
for(int k = 0; k < cnt; k++){
if((1 << k) & i) continue;
if(dis[j][k] > dp[i][j]) continue;
dp[i | (1 << k)][k] = max(dp[i][j] - dis[j][k], dp[i | (1 << k)][k]);
if(bettery[k]) dp[i | (1 << k)][k] = st;
}
}
} return false;
} int main(){
while(~scanf("%d%d", &n, &m) && n + m){
cnt = 0;
Fin = 0;
int tmp = 0;
memset(bettery, 0, sizeof(bettery));
for(int i = 0; i < n; i++){
scanf("%s", mp[i]);
for(int j = 0; j < m; j++){
if(mp[i][j] == 'F'){
sx = i, sy = j;
}
else if(mp[i][j] == 'G'){
bettery[cnt] = 1;
id[i * m + j] = cnt++;
}
else if(mp[i][j] == 'Y'){
Fin += (1 << cnt);
id[i * m + j] = cnt++;
tmp++;
}
}
}
id[sx * m + sy] = cnt; if(tmp == 0){
printf("0\n");
continue;
} memset(dis, INF, sizeof(dis));
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
if(mp[i][j] != 'D' && mp[i][j] != 'S')
bfs(i, j);
}
} int l = 0, r = 1000000;
int ans = -1;
while(l <= r){
int m = (l + r) >> 1;
if(check(m)){
r = m - 1;
ans = m;
}
else l = m + 1;
}
printf("%d\n", ans);
}
return 0;
}

HDU 3681 Prison Break(状压DP + BFS)题解的更多相关文章

  1. hdu 3247 AC自动+状压dp+bfs处理

    Resource Archiver Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 100000/100000 K (Java/Ot ...

  2. HDU 4272 LianLianKan(状压DP)题解

    题意:一个栈,每次可以选择和栈顶一样的数字,并且和栈顶距离小于6,然后同时消去他们,问能不能把所有的数消去 思路:一个数字最远能消去和他相距9的数,因为中间4个可以被他上面的消去.因为还要判断栈顶有没 ...

  3. HDU 4628 Pieces(状压DP)题解

    题意:n个字母,每次可以删掉一组非连续回文,问你最少删几次 思路:把所有回文找出来,然后状压DP 代码: #include<set> #include<map> #includ ...

  4. hdu 2825 aC自动机+状压dp

    Wireless Password Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others ...

  5. BZOJ_3049_[Usaco2013 Jan]Island Travels _状压DP+BFS

    BZOJ_3049_[Usaco2013 Jan]Island Travels _状压DP+BFS Description Farmer John has taken the cows to a va ...

  6. HDU 3247 Resource Archiver(AC自动机 + 状压DP + bfs预处理)题解

    题意:目标串n( <= 10)个,病毒串m( < 1000)个,问包含所有目标串无病毒串的最小长度 思路:貌似是个简单的状压DP + AC自动机,但是发现dp[1 << n][ ...

  7. HDU 5765 Bonds(状压DP)

    [题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=5765 [题目大意] 给出一张图,求每条边在所有边割集中出现的次数. [题解] 利用状压DP,计算不 ...

  8. hdu 4778 Gems Fight! 状压dp

    转自wdd :http://blog.csdn.net/u010535824/article/details/38540835 题目链接:hdu 4778 状压DP 用DP[i]表示从i状态选到结束得 ...

  9. HDU 4272 LianLianKan (状压DP+DFS)题解

    思路: 用状压DP+DFS遍历查找是否可行.假设一个数为x,那么他最远可以消去的点为x+9,因为x+1~x+4都能被他前面的点消去,所以我们将2进制的范围设为2^10,用0表示已经消去,1表示没有消去 ...

随机推荐

  1. git的使用学习笔记---分支删除

    一.使用场景: 1.修改bug,原来分支不管用 2,分支太多不易管理 二.方法 git branch -d branch1 无法删除:原因在与该分支为目前工作的分支,所以要切换分支 git check ...

  2. 2 安装部署flume

    本文对flume进行安装部署 flume是什么?传送门:https://www.cnblogs.com/zhqin/p/12230301.html 0.要安装部署在日志所在的服务器,或者把日志发送到日 ...

  3. maven打包三种方式

    https://blog.csdn.net/w820896059/article/details/80423143

  4. TCMalloc源码学习(四)(小内存块释放)

    pagemap_和pagemap_cache_ PageHeap有两个map,pagemap_记录某一内存页对应哪一个span,显然可能多页对应一个span,pagemap_cache_记录某一内存页 ...

  5. P6739 [BalticOI 2014 Day1] Three Friends 题解

    目录 写在前面 Solution 何为字符串哈希(可跳过): Code 写在前面 P6739 [BalticOI 2014 Day1] Three Friends 听说这题可以用比较暴力的做法过,比如 ...

  6. docker镜像加速,docker更换为国内镜像

    docker镜像加速,docker更换为国内镜像 一.使用官方镜像 二.Docker守护进程配置加速器 相关博文原文地址: CSDN:让我思考一下 :docker更换为国内镜像 一.使用官方镜像 Do ...

  7. GeoMesa 环境搭建

    GeoMesa 环境搭建 版本 虚拟机安装 os centos7 Centos安装 CentOS安装Jdk并配置环境变量 hadoop.hbase环境部署 geomesa_hbase部署 geoser ...

  8. 将文件转成byte[]文件属组

    /** * * @Description : 读取文件数组 * @Method_Name : fileBuff * @param filePath * @return * @throws IOExce ...

  9. 利用Java反射机制将Bean转成Map

    import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang ...

  10. 图的深度优先遍历算法(DFS)

    搜索算法有很多种,本次文章主要分享图(无向图)的深度优先算法.深度优先算法(DFS)主要是应用于搜索中,早期是在爬虫中使用.其主要的思想有如下: 1.先访问一个节点v,然后标记为已被访问过2.找到第一 ...