题目链接: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的更多相关文章

  1. 计蒜客模拟赛D1T3 蒜头君的坐骑:用dfs转移dp

    题目链接:https://nanti.jisuanke.com/t/16447 题意: 蒜头君有一只坐骑,人马. 一天,蒜头君骑着他的坐骑走上了一片n*m的大荒野,一开始时,蒜头君在(1,1)点,他要 ...

  2. 计蒜客模拟赛D2T2 蒜头君的排序:区间逆序对(移动端点) + 树状数组

    题目链接:https://nanti.jisuanke.com/t/16443 题意: 给你一个由1~n构成的正整数序列,有m组询问,每组询问要求输出[l , r]区间内的逆序对个数. 数据范围: 对 ...

  3. 计蒜客模拟赛D2T1 蒜头君的兔子:矩阵快速幂

    题目链接:https://nanti.jisuanke.com/t/16442 题意: 有个人在第一年送了你一对1岁的兔子.这种兔子刚生下来的时候算0岁,当它在2~10岁的时候,每年都会生下一对兔子, ...

  4. 计蒜客模拟赛D1T2 蒜头君的树:树上节点之间最短距离和

    题目链接:https://nanti.jisuanke.com/t/16446 题意: 给你一棵有n个节点的树以及每条边的长度,输出树上节点之间的最短距离和.然后进行m次操作,每次操作更改一条边的长度 ...

  5. 计蒜客模拟赛D1T1 蒜头君打地鼠:矩阵旋转+二维前缀和

    题目链接:https://nanti.jisuanke.com/t/16445 题意: 给你一个n*n大小的01矩阵,和一个k*k大小的锤子,锤子只能斜着砸,问只砸一次最多能砸到多少个1. 题解: 将 ...

  6. 计蒜客模拟赛5 D2T1 成绩统计

    又到了一年一度的新生入学季了,清华和北大的计算机系同学都参加了同一场开学考试(因为两校兄弟情谊深厚嘛,来一场联考还是很正常的). 不幸的是,正当老师要统计大家的成绩时,世界上的所有计算机全部瘫痪了. ...

  7. 计蒜客模拟赛5 D2T2 蚂蚁搬家

    很久很久以前,有很多蚂蚁部落共同生活在一片祥和的村庄里.但在某一天,村庄里突然出现了一只食蚁兽,蚂蚁们为了保全性命而决定搬家. 然而这个村庄四面环山,想要离开这个村庄必须要从地洞里离开,村子里一共有 ...

  8. 计蒜客模拟赛 #5 (B 题) 动态点分治+线段树

    虽然是裸的换根dp,但是为了在联赛前锻炼码力,强行上了点分树+线段树. 写完+调完总共花了不到 $50$ 分钟,感觉还行. code: #include <bits/stdc++.h> # ...

  9. 2019牛客多校第五场 F maximum clique 1 状压dp+最大独立集

    maximum clique 1 题意 给出一个集合s,求每个子集的最大独立集的权值和(权值是独立集的点个数) 分析 n比较小,一股浓浓的暴力枚举每一个子集的感觉,但是暴力枚举模拟肯定会T,那么想一想 ...

随机推荐

  1. 闭包JS

    一句话概括的话:闭包就是一个函数,捕获作用域内的外部绑定. 官方的定义:一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因为这些变量也称为该表达式的一部分. 自由变量和闭包的关系:自 ...

  2. HDU 1814 Peaceful Commission / HIT 1917 Peaceful Commission /CJOJ 1288 和平委员会(2-sat模板题)

    HDU 1814 Peaceful Commission / HIT 1917 Peaceful Commission /CJOJ 1288 和平委员会(2-sat模板题) Description T ...

  3. mysql主从数据库设置备忘

    [mysqld] binlog-do-db = databasename1 binlog-do-db = databasename2 binlog-do-db = databasename3 -- 且 ...

  4. SQL Server 2012 案例教程(贾祥素)——学习笔记

    第2章 SQL Server 2012概述 1.SQL(Structed Query Language),结构化查询语言. 2.SSMS(SQL Server Mangement Studio),SQ ...

  5. nyoj_3:多边形重心问题(计算几何)

    基础的计算几何 多边形的n个顶点按*时针方向给出 由任意n边形可分解为n-2个三角形,各三角形面积面积与重心易得,故有各三角形的面积及重心 用重心公式可求得多边形的面积与重心 题目链接: http:/ ...

  6. .Net中关于相等的问题

    在.Net框架中,如果您查看所有类型的的基类:System.Object类,将找到如下4个与相等判断的方法: static Equals() virtual Equals() static Refer ...

  7. maven依赖jar包更新,业务jar需同步更新(业务jar依赖API)

    背景: 环境出现问题,定位为依赖jar缺失,修改工程pom文件补充依赖jar. 更新要点说明: 依赖jar,更新提交 业务jar,也需更新提交:maven构建会把依赖jar引用进去,更新环境如果单独更 ...

  8. 一些重要 Docker 命令的简单介绍

    1. 拉取 Docker 镜像 由于容器是由 Docker 镜像构建的,首先我们需要拉取一个 docker 镜像来开始.我们可以从 Docker Registry Hub 获取所需的 docker 镜 ...

  9. Mybatis Mapper.java和Mapper.xml能否分离问题

    Mybatis Mapper.java和Mapper.xml是能分离的. 从图上不难看出,不管是/java还是/resources,他们最终编译后的存放路径均是/target/classes 因此将x ...

  10. spring 页面跳转

    RedirectAttributes  的两个方式的获取总结:1:addFlashAttribute @RequestMapping(value="hello") public S ...