计蒜客模拟赛D2T3 蒜头君救人:用bfs转移状压dp
题目链接:https://nanti.jisuanke.com/t/16444
题意:
蒜头君是一个乐于助人的好孩子,这天他所在的乡村发生了洪水,有多名村民被困于孤岛上,于是蒜头君决定去背他们离开困境,假设蒜头君所在的村子是n*m的网格,网格中.号代表平地,#号代表该地已被洪水淹没,A、B……等大写字母表示该地有村民被困,s代表蒜头君的起点,t代表蒜头君的终点。
蒜头君的初始速度为 k秒一格,他每次可以向上下左右4个方向中的一个移动1格。在背上一个村民后,他的速度可能会降低,也可能会加快,但他的速度不能快于1秒每格,那么蒜头君想知道,他最快需要多长时间将所有村民救出?
注意:不能在终点以外的地方放下村民;可以同时背多个村民。
题解:
用dp[state][x][y]表示现在在(x , y)这个点,村民的状态为state。state是一个三进制数,每一位对应一个村民,0表示村民还在原地,1表示正在背着这个村民,2表示这个村民已经到达终点。
显然,应该先枚举村民状态state,再枚举当前位置(x , y)。但本题和一般的网格dp不同,起点并不一定在左上角(1 , 1)处,而且并不是只能走右和下两个方向,因此本题需要从起点开始bfs,对于每一个被更新dp值的状态,都需要加入队列中。
下面考虑如何转移。
如果当前地点为'.'(平地),那么state不变,向上下左右四个方向转移(不能是'#'),dp[state][...][...](上下左右) = min(dp[state][...][...] , dp[state][x][y] + cal_spd(state)),cal_spd(state)计算的是在当前状态时自己的速度。
如果当前地点为大写字母(有村民要救),并且当前state中这个村民还在原地,那么可以背上这个村民,dp[state_pick][x][y] = min(dp[state_pick][x][y] , dp[state][x][y]),state_pick为在当前state下再背上这个村民时的状态。
如果现在在终点t,很明显只有两种选择,一种是放下所有会让我减速的村民(能让我加速的村民肯定要一直背到底),一种是放下全部的村民(结束救人)。两种转移后的状态分别为state_part和state_all,那么dp[state_part][x][y] = min(dp[state_part][x][y] , dp[state][x][y]),dp[state_all][x][y] = min(dp[state_all][x][y] , dp[state][x][y])。
AC Code:
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <queue>
#define MAX_N 15
#define MAX_S 60000
#define MAX_A 30
#define INF 10000000 using namespace std; const int POW[]={,,,,,,,,,,,,}; struct Coor
{
int x;
int y;
Coor(int _x,int _y)
{
x=_x;
y=_y;
}
Coor(){}
}; struct sta
{
int state;
int x;
int y;
sta(int _state,int _x,int _y)
{
state=_state;
x=_x;
y=_y;
}
sta(){}
}; int n,m,k;
int cnt=;
int spd[MAX_A];
int dp[MAX_S][MAX_N][MAX_N];
char c[MAX_N][MAX_N];
bool vis[MAX_S][MAX_N][MAX_N];
Coor start;
Coor over;
queue<sta> q; inline int update(int &v,int k,int a)
{
return v=v-((v/POW[k])%)*POW[k]+a*POW[k];
} inline int query(int v,int k)
{
return (v/POW[k])%;
} void read()
{
cin>>n>>m>>k;
for(int i=;i<=n;i++)
{
for(int j=;j<=m;j++)
{
cin>>c[i][j];
if(c[i][j]=='s') start=Coor(i,j);
if(c[i][j]=='t') over=Coor(i,j);
if(isupper(c[i][j])) cnt++;
}
}
for(int i=;i<cnt;i++)
{
char ch;
int speed;
cin>>ch>>speed;
spd[i]=speed;
}
} int cal_spd(int state)
{
int sum=k;
for(int i=;i<cnt;i++)
{
int val=query(state,i);
if(val==) sum+=spd[i];
}
return sum>=?sum:;
} bool is_legal(int x,int y)
{
return c[x][y]!='#' && x> && x<=n && y> && y<=m;
} int set_part(int state)
{
for(int i=;i<cnt;i++)
{
if(spd[i]<=) continue;
int val=query(state,i);
if(val==) update(state,i,);
}
return state;
} int set_all(int state)
{
for(int i=;i<cnt;i++)
{
int val=query(state,i);
if(val==) update(state,i,);
}
return state;
} int pick_up(int state,int k)
{
return update(state,k,);
} void init_dp()
{
for(int state=;state<POW[cnt];state++)
{
for(int i=;i<=n;i++)
{
for(int j=;j<=m;j++)
{
dp[state][i][j]=INF;
}
}
}
dp[][start.x][start.y]=;
} sta get_front()
{
sta now=q.front();
q.pop();
vis[now.state][now.x][now.y]=false;
return now;
} void insert(sta now)
{
if(vis[now.state][now.x][now.y]) return;
q.push(now);
vis[now.state][now.x][now.y]=true;
} void bfs(sta start)
{
memset(vis,false,sizeof(vis));
insert(start);
while(!q.empty())
{
sta now=get_front();
int x=now.x;
int y=now.y;
int state=now.state;
int speed=cal_spd(state);
if(is_legal(x+,y) && dp[state][x+][y]>dp[state][x][y]+speed)
{
dp[state][x+][y]=dp[state][x][y]+speed;
insert(sta(state,x+,y));
}
if(is_legal(x-,y) && dp[state][x-][y]>dp[state][x][y]+speed)
{
dp[state][x-][y]=dp[state][x][y]+speed;
insert(sta(state,x-,y));
}
if(is_legal(x,y+) && dp[state][x][y+]>dp[state][x][y]+speed)
{
dp[state][x][y+]=dp[state][x][y]+speed;
insert(sta(state,x,y+));
}
if(is_legal(x,y-) && dp[state][x][y-]>dp[state][x][y]+speed)
{
dp[state][x][y-]=dp[state][x][y]+speed;
insert(sta(state,x,y-));
}
if(c[x][y]=='t')
{
int state_part=set_part(state);
if(dp[state_part][x][y]>dp[state][x][y])
{
dp[state_part][x][y]=dp[state][x][y];
insert(sta(state_part,x,y));
}
int state_all=set_all(state);
if(dp[state_all][x][y]>dp[state][x][y])
{
dp[state_all][x][y]=dp[state][x][y];
insert(sta(state_all,x,y));
}
}
if(isupper(c[x][y]))
{
int state_pick=pick_up(state,c[x][y]-'A');
if(dp[state_pick][x][y]>dp[state][x][y])
{
dp[state_pick][x][y]=dp[state][x][y];
insert(sta(state_pick,x,y));
}
}
}
} void solve()
{
init_dp();
bfs(sta(,start.x,start.y));
} void print()
{
cout<<dp[POW[cnt]-][over.x][over.y]<<endl;
} int main()
{
read();
solve();
print();
}
计蒜客模拟赛D2T3 蒜头君救人:用bfs转移状压dp的更多相关文章
- 计蒜客模拟赛D1T3 蒜头君的坐骑:用dfs转移dp
题目链接:https://nanti.jisuanke.com/t/16447 题意: 蒜头君有一只坐骑,人马. 一天,蒜头君骑着他的坐骑走上了一片n*m的大荒野,一开始时,蒜头君在(1,1)点,他要 ...
- 计蒜客模拟赛D2T2 蒜头君的排序:区间逆序对(移动端点) + 树状数组
题目链接:https://nanti.jisuanke.com/t/16443 题意: 给你一个由1~n构成的正整数序列,有m组询问,每组询问要求输出[l , r]区间内的逆序对个数. 数据范围: 对 ...
- 计蒜客模拟赛D2T1 蒜头君的兔子:矩阵快速幂
题目链接:https://nanti.jisuanke.com/t/16442 题意: 有个人在第一年送了你一对1岁的兔子.这种兔子刚生下来的时候算0岁,当它在2~10岁的时候,每年都会生下一对兔子, ...
- 计蒜客模拟赛D1T2 蒜头君的树:树上节点之间最短距离和
题目链接:https://nanti.jisuanke.com/t/16446 题意: 给你一棵有n个节点的树以及每条边的长度,输出树上节点之间的最短距离和.然后进行m次操作,每次操作更改一条边的长度 ...
- 计蒜客模拟赛D1T1 蒜头君打地鼠:矩阵旋转+二维前缀和
题目链接:https://nanti.jisuanke.com/t/16445 题意: 给你一个n*n大小的01矩阵,和一个k*k大小的锤子,锤子只能斜着砸,问只砸一次最多能砸到多少个1. 题解: 将 ...
- 计蒜客模拟赛5 D2T1 成绩统计
又到了一年一度的新生入学季了,清华和北大的计算机系同学都参加了同一场开学考试(因为两校兄弟情谊深厚嘛,来一场联考还是很正常的). 不幸的是,正当老师要统计大家的成绩时,世界上的所有计算机全部瘫痪了. ...
- 计蒜客模拟赛5 D2T2 蚂蚁搬家
很久很久以前,有很多蚂蚁部落共同生活在一片祥和的村庄里.但在某一天,村庄里突然出现了一只食蚁兽,蚂蚁们为了保全性命而决定搬家. 然而这个村庄四面环山,想要离开这个村庄必须要从地洞里离开,村子里一共有 ...
- 计蒜客模拟赛 #5 (B 题) 动态点分治+线段树
虽然是裸的换根dp,但是为了在联赛前锻炼码力,强行上了点分树+线段树. 写完+调完总共花了不到 $50$ 分钟,感觉还行. code: #include <bits/stdc++.h> # ...
- 2019牛客多校第五场 F maximum clique 1 状压dp+最大独立集
maximum clique 1 题意 给出一个集合s,求每个子集的最大独立集的权值和(权值是独立集的点个数) 分析 n比较小,一股浓浓的暴力枚举每一个子集的感觉,但是暴力枚举模拟肯定会T,那么想一想 ...
随机推荐
- Nio经典工作方式
public void selector() throws IOException { ByteBuffer buffer = ByteBuffer.allocate(1024); Selector ...
- UML 解析
UML 解析 泛化 表示类与类之间的继承关系.接口与接口之间的继承关系: 实现 表示类对接口的实现 依赖 当类与类之间有使用关系时就属于依赖关系,不同于关联关系,依赖不具有"拥有关系&quo ...
- 前端需要注意的seo
1 合理的title ,description ,keyswords 搜索引擎对这三项的权重逐渐减小,title 强调重点即可 ,重要的关键字不要超过两次,而且要靠前. 2 不同的tilte要有所不同 ...
- BOM浏览器对象模型下面几个比较实用的方法
location对象 location.href-- 返回或设置当前文档的URL location.search -- 返回URL中的查询字符串部分.例如 http://www.dreamdu.com ...
- Struts2的知识点小总结
strust2是 struts1和webwork的结合 (本质相当于servlet) 核心:拦截器 interceptor action ognl和valuestack 使用struts的准备工作 ...
- 原生JS的HTTP请求
ar xhr = new XMLHttpRequest(); xhr.onreadystatechange = function(){ if( xhr.readyState == 4){ if( xh ...
- linux可用更新源
Kali 2.0更新源kali-rolling:#中科大deb http://mirrors.ustc.edu.cn/kali kali-rolling main non-free contribde ...
- javascript事件轮询
JavaScript 运行机制详解:再谈Event Loop 一.为什么JavaScript是单线程? JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事.那么,为什么Ja ...
- Java代码优化六大原则
单一职责 代码优化第一步,单一职责原则 (Single Responsibility Principle).对于一个Java类,应该仅有一个引起它变化的原因,也就是说,一个类中,应该是一组相关性很高的 ...
- jenkins+ANT+jmeter 接口测试环境搭建
目的 jmeter很早就接触了,最近又在接触项目的时候整了一下.写这篇博客主要有两个目的 1,为了给自己搭建jmeter做一个总结. 2,在部署过程中遇到过一些坑,在这分享出来,也希望能给需要的人一个 ...