HDU 3681 Prison Break 越狱(状压DP,变形)
题意:
给一个n*m的矩阵,每个格子中有一个大写字母,一个机器人从‘F’出发,拾取所有的开关‘Y’时便能够越狱,但是每走一格需要花费1点能量,部分格子为充电站‘G’,每个电站只能充1次电。而且部分格子为障碍'D'或者空格‘S’。机器人在开始时电池是满能量的,问电池容量至少为多少可以越狱?(1<=n,m<=14,充电站+开关的总个数<=15)
思路:
看错题了,以为充电站和开关的个数分别至多为14,其实是两种加起来14。
既然只有15个关键的格子,那么状压就有用了。假设每个点关键格必须走1次,那么就像可重复走的TSP了。但是充电站只能充1次,而且路过了也可以不充。所以,其实关键格只有那些“开关”,只要保证所有开关都收集全了,其他都无所谓。
具体做法,求出这15个格子(包括起点)的两两之间的距离(BFS就够了),相当于一个完全连通图。再二分答案,判断是否能够收集所有开关。判断能否收集开关,就相当于求所有点只能走1次的欧拉路径了,直接状态压缩来求,注意:两点间不一定可达,遇到充电站必须充满电。这样子对于一个格子具体走过了多少格已经没有关系了。
//#include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <deque>
#include <map>
#include <algorithm>
#include <vector>
#include <iostream>
#define pii pair<int,int>
#define INF 0x3f3f3f3f
#define LL long long
#define ULL unsigned long long
using namespace std;
const double PI = acos(-1.0);
const int N=;
int dp[<<][N], tag[N][N], vis[N][N], dis[N][N], n, m, egy;
char g[N][N]; struct node
{
int x,y,d;
node(){};
node(int x,int y,int d):x(x),y(y),d(d){};
};
inline bool istar(int x,int y){return tag[x][y]>;}
inline bool isok(int x,int y){ return (x>&&x<=n)&&(y>&&y<=m)&&g[x][y]!='D';}
inline int cmp(node a,node b){ return g[a.x][a.y]<g[b.x][b.y];}
bool binary(int cap)
{
memset(dp,-,sizeof(dp));
dp[][]=cap;
for(int s=; s<(<<n); s++)
{
for(int i=; i<=n; i++)
{
if( (s&(<<i-))== ) continue; //未走
for(int j=; j<=n; j++)
{
if( s&(<<j-) ) continue; //只能走1次
int add= j<=egy?cap:-;
if( dis[i][j]> && dp[s][i]>=dis[i][j] ) //前提要走得到那个位置
dp[s|(<<j-)][j]=max(dp[s|(<<j-)][j], max(dp[s][i]-dis[i][j],add));
}
}
}
int mod=(<<n)-(<<egy)+, ans=-INF;
for(int s=; s<(<<n); s++)
{
if( (s&mod)==mod )
{
for(int i=; i<=n; i++)
ans=max(ans, dp[s][i]);
}
}
return ans>=;
} deque<node> que;
void BFS(int x,int y) //求最短路
{
memset(vis,,sizeof(vis));
que.clear();
que.push_back(node(x,y,));
vis[x][y]=true;
while(!que.empty())
{
node t=que.front();que.pop_front();
if( istar(t.x,t.y) ) //记录最短路
dis[tag[x][y]][tag[t.x][t.y]]=t.d;
if(isok(t.x-,t.y)&&!vis[t.x-][t.y])
{
que.push_back(node(t.x-,t.y,t.d+) );
vis[t.x-][t.y]=true;
}
if(isok(t.x+,t.y)&&!vis[t.x+][t.y])
{
que.push_back(node(t.x+,t.y,t.d+) );
vis[t.x+][t.y]=true;
}
if(isok(t.x,t.y-)&&!vis[t.x][t.y-])
{
que.push_back(node(t.x,t.y-,t.d+) );
vis[t.x][t.y-]=true;
}
if(isok(t.x,t.y+)&&!vis[t.x][t.y+])
{
que.push_back(node(t.x,t.y+,t.d+) );
vis[t.x][t.y+]=true;
}
}
} int cal()
{
vector<node> vect; //关键点
for(int i=; i<=n; i++) //编号
for(int j=; j<=m; j++)
if(g[i][j]!='S'&&g[i][j]!='D')
vect.push_back(node(i,j,)); sort(vect.begin(), vect.end(), cmp); //按字典序排序
for(int i=; i<vect.size(); i++) //编号
tag[vect[i].x][vect[i].y]=i+; egy=;
for(int i=; i<vect.size(); i++)
{
if(g[vect[i].x][vect[i].y]=='G') egy++;
BFS(vect[i].x,vect[i].y); //计算最短路
}
n=vect.size();
if(egy==n) return ; //无开关?
if(!binary()) return -; //不可达 int L=, R=;
while(L<R) //二分答案
{
int mid=R-(R-L+)/;
if( binary(mid) ) R=mid;
else L=mid+;
}
return R;
} int main()
{
//freopen("input.txt","r",stdin);
while(scanf("%d%d",&n,&m), n+m)
{
memset(tag,,sizeof(tag));
memset(dis,-,sizeof(dis)); for(int i=; i<=n; i++) scanf("%s",g[i]+);
printf("%d\n",cal());
}
return ;
}
AC代码
HDU 3681 Prison Break 越狱(状压DP,变形)的更多相关文章
- HDU 3681 Prison Break(状压DP + BFS)题解
题意:一张图,F是起点,Y是必须要到的点,D不能走,G可以充电.可以往四个方向走,每走一步花费一个电,走到G可以选择充满电或者不充,每个G只能充一次.问你走遍Y的最小初始点亮.number(G) + ...
- HDU 3681 Prison Break(状态压缩dp + BFS)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3681 前些天花时间看到的题目,但写出不来,弱弱的放弃了.没想到现在学弟居然写出这种代码来,大吃一惊附加 ...
- HDU-3681-Prison Break(BFS+状压DP+二分)
Problem Description Rompire is a robot kingdom and a lot of robots live there peacefully. But one da ...
- HDU 6149 Valley Numer II 状压DP
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6149 题意:中文题目 解法:状压DP,dp[i][j]代表前i个低点,当前高点状态为j的方案数,然后枚 ...
- HDU 5434 Peace small elephant 状压dp+矩阵快速幂
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5434 Peace small elephant Accepts: 38 Submissions: ...
- HDU 1074 Doing Homework(状压DP)
第一次写博客ORZ…… http://acm.split.hdu.edu.cn/showproblem.php?pid=1074 http://acm.hdu.edu.cn/showproblem.p ...
- HDU 4906 Our happy ending (状压DP)
HDU 4906 Our happy ending pid=4906" style="">题目链接 题意:给定n个数字,每一个数字能够是0-l,要选当中一些数字.然 ...
- HDU 1074 Doing Homework (状压dp)
题意:给你N(<=15)个作业,每个作业有最晚提交时间与需要做的时间,每次只能做一个作业,每个作业超出最晚提交时间一天扣一分 求出扣的最小分数,并输出做作业的顺序.如果有多个最小分数一样的话,则 ...
- HDU 4568 Hunter 最短路+状压DP
题意:给一个n*m的格子,格子中有一些数,如果是正整数则为到此格子的花费,如果为-1表示此格子不可到,现在给k个宝藏的地点(k<=13),求一个人从边界外一点进入整个棋盘,然后拿走所有能拿走的宝 ...
随机推荐
- Laravel中使用Session存取验证码信息
1.将验证码存储到session中. $request->session()->put('validate_code',$validateCode->getCode());//存储信 ...
- SQL中SUM函数和CASE WHEN联合使用
SELECT SUM(case WHEN sex=1 then 1 else 0 end )as '男生', SUM(case when sex =2 then 1 else 0 end )'女生'F ...
- PHP中GD库是做什么用的? PHP GD库介绍11111111
什么是gd库? gd库是php处理图形的扩展库,gd库提供了一系列用来处理图片的API,使用GD库可以处理图片,或者生成图片. 在网站上GD库通常用来生成缩略图或者用来对图片加水印或者对网站数据 ...
- Codeforces Round #299 (Div. 2)【A,B,C】
codeforces 535A-水题: #include <bits/stdc++.h> using namespace std; typedef long long LL; char s ...
- unity3d各种OpenFileDialog操作
http://www.cnblogs.com/U-tansuo/archive/2012/07/10/GetOpenFileName.html 1 编辑模式(Editor)下: string path ...
- 洛谷P2029 跳舞
P2029 跳舞 题目描述 小明今天得到一个跳舞毯游戏程序Dance.游戏每次连续出N个移动的“箭头”,箭头依次标号为1到N,并且的相应的分数S[1..N].如果你能“踏中”第i号箭头,你将获得相应的 ...
- 洛谷P1654 产品排序(sort)
P1654 产品排序(sort) 题目描述 有一系列产品,给定每个产品的加工时间和冷却成型时间(冷却过程产品之间没有关系,是单独冷却的).现在你手上有两台机器可以用来加工,你需要安排产品加工的顺序以及 ...
- Java 多线程高并发编程 笔记(一)
本篇文章主要是总结Java多线程/高并发编程的知识点,由浅入深,仅作自己的学习笔记,部分侵删. 一 . 基础知识点 1. 进程于线程的概念 2.线程创建的两种方式 注:public void run( ...
- java CDI
Scope声明周期 http://www.cnblogs.com/yjmyzz/p/javaee-cdi-bean-scope.html
- 黑马旅游网配置 pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://mave ...