题目链接: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. [图形学] Chp18 OpenGL表面纹理函数

    以2D表面为例展示纹理贴图,用opengl设置一个2D纹理,颜色存储在32*32*3的数组中,对应的纹理坐标为0<=s, t<=1.0. 画出几个正方形表面,分别以GL_CLAMP(纹理坐 ...

  2. unslider插件的使用

    深入理解unslider.js源码 最近用到了一个挺好用的幻灯片插件,叫做unslider.js,就想看看怎么实现幻灯片功能,就看看源码,顺便自己也学习学习.看完之后收获很多,这里和大家分享一下. u ...

  3. 针对双系统ubuntu16.04卡死及系统没有声音解决方法

    楼主电脑系统状况:win10主系统,128固态为ubuntu系统       安装一共为两次. 第一次出现ubuntu安装成功后没有声音,主系统win10有声音,Ubuntu上检测不到声卡,说明ubu ...

  4. App Extensions篇之Sticker Pack Extension

    转载请标明原文链接:http://www.cnblogs.com/zhanggui/p/7151795.html 前言 上一篇文章对App Extension做了简单介绍以及对Share Extens ...

  5. 对于所有对象都通用方法的解读(Effective Java 第二章)

    这篇博文主要介绍覆盖Object中的方法要注意的事项以及Comparable.compareTo()方法. 一.谨慎覆盖equals()方法 其实平时很少要用到覆盖equals方法的情况,没有什么特殊 ...

  6. POJ 3342 Party at Hali-Bula / HDU 2412 Party at Hali-Bula / UVAlive 3794 Party at Hali-Bula / UVA 1220 Party at Hali-Bula(树型动态规划)

    POJ 3342 Party at Hali-Bula / HDU 2412 Party at Hali-Bula / UVAlive 3794 Party at Hali-Bula / UVA 12 ...

  7. 如何清除img图片下面有一片空白

    最近在做项目突然发现用了img后有个空白区,如下图: 真的很影响美观,那么是什么原因造成的呢? 右键查看元素查看上下文的margin和padding也没有找到这个空白的来源. 只好上网看看别人是怎么说 ...

  8. 个人作业2--英语学习APP案例分析

    1.下载APP并使用,上手体验 个人很喜欢这种风格,画面简洁,排版精细,尤其是联想词的界面,很惊喜.但是很多链接比如精选文章点进去之后的UI设计并不理想,感觉只是一个网页而已.并且我不能够保存或者收藏 ...

  9. FTP服务器 Serv-u 环境搭建

    一.安装 *Windows 10 *Serv-u Windows-v15.1.2 *Mysql Mysql 5.7 安装成功后开始配置serv-u. 二.配置 1.新建域(test) 点击新建域,开始 ...

  10. aspcms多图调用以及错误提示:3704

    1.“为师资介绍”(相册列表)建立了内容页(相册内容页), 需要对模板页面改造,在相册详细页调用多图,之前没有试过,这次利用: 实现多图调用,注意不能使用contentid=[content:id]  ...