蒜头君救人

题目描述

蒜头君是一个乐于助人的好孩子,这天他所在的乡村发生了洪水,有多名村民被困于孤岛上,于是蒜头君决定去背他们离开困境,假设蒜头君所在的村子是 n×m n×m 的网格,网格中.号代表平地,#号代表该地已被洪水淹没,A、B……等大写字母表示该地有村民被困,s代表蒜头君的起点,t代表蒜头君的终点。

蒜头君的初始速度为 k 秒一格,他每次可以向上下左右 4 个方向中的一个移动 1 格。在背上一个村民后,他的速度可能会降低,也可能会加快,但他的速度不能快于 1 秒每格,那么蒜头君想知道,他最快需要多长时间将所有村民救出?

注意:不能在终点以外的地方放下村民;可以同时背多个村民。

输入格式

第一行 3 个正整数 n,m(1≤n,m≤10),k n,m(1 \le n,m \le 10),k,分别表示村庄长度、宽度、蒜头君初始速度。

接下来 n n行,每行一个长度为mm 的字符串,表示村庄的地形,字符串意义如上所述。

接下来若干行,每行一个大写字母、一个整数,表示该编号的村民会使 k k 增加 / 减少多少。行数等同于地形中大写字母的个数。大写字母按字典序,即A、B、C的顺序排列,保证前后两行的字母是连续的,村民个数小于等于 10。

输出格式

输出 1 个整数,表示最小用时。

样例输入

4 4 2
s.##
..A#
.B##
…t
A -3
B 4

样例输出

17


数据规模这么小,不是搜索就是状压。

标程给出的是三进制状压DP,但是这样做使得位运算的优势不复存在了。所以时间复杂度其实也只是理性愉悦,提取某一位常数很大。而且也增加了编程复杂度。

事实上二进制状压DP是可以的,并不会达到 O(4cntcnt2) O(4^{cnt}cnt^2)的复杂度,而且跑得很快。

定义状态 f[S1][S2][p] f[S_1][S_2][p]表示背着的村民状态为 S1 S_1,已经到终点的村民为 S2 S_2,蒜头君处在 p p位置(pp只取初始状态下村民的位置、终点位置),那么显然有状态转移:

f[S1|(1<<y−1)][S2][y]=min(dis(x,y)V[S1]+f[S1][S2][x])

f[S_1|(1

(x∉S2,x∈S1,y∉S2,y∉S1)

(x\notin S_2,x\in S_1,y\notin S_2,y\notin S_1)

f[S1xorT][S2|T][en]=min(f[S1xorT][S2|T][en],f[S1][S2][en])

f[S_1 xor T][S_2|T][en]=min(f[S_1 xor T][S_2|T][en],f[S_1][S_2][en])

(T∈S1,en为终点)

(T\in S_1,en为终点)

V[S] V[S]表示在背着的村民状态为 S S下的速度,dis(x,y)dis(x,y)表示在原图上 x,y x,y的距离。都可以预处理出来。下面的代码采用的是floyd求距离,当然也可以用BFS。

上述两式分别表示到一个地方接村民、在终点放村民。如果不用记忆化搜索的形式,注意循环顺序。

那么为什么跑得很快呢?因为在这样的定义下, S1 S_1与 S2 S_2是不能有交集的,这样显然不可能的情况在循环里判断一下就可以了,实际上可能合法的情况只有 3cnt 3^{cnt}种。再加上 x,y x,y与两个集合间的关系,循环执行的次数不会特别多。


代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;int N,M,K,dx[4]={0,0,1,-1},dy[4]={-1,1,0,0};
int Map[105][105],pos[15],id[15][15],tot,v[15];
int f[1234][1234][15],V[1234],U,inf;
char s[15][15];int main()
{int i,j,k,x,y,tx,ty,St;char ch[3];scanf("%d%d%d",&N,&M,&K);for(i=1;i<=N;i++)scanf("%s",&s[i][1]);while(scanf("%s%d",ch,&x)!=EOF)v[++v[0]]=x;for(i=1;i<=N;i++)for(j=1;j<=M;j++)id[i][j]=++tot;for(i=1;i<=tot;i++)for(j=1;j<=tot;j++)Map[i][j]=1e9;for(i=1;i<=tot;i++)Map[i][j]=0;for(i=1;i<=N;i++)for(j=1;j<=M;j++){if(s[i][j]=='#')continue;x=i;y=j;for(k=0;k<4;k++){tx=x+dx[k];ty=y+dy[k];if(tx&&ty&&tx<=N&&ty<=M&&s[tx][ty]!='#'){int a=id[x][y],b=id[tx][ty];Map[a][b]=1;}}}for(k=1;k<=tot;k++)for(i=1;i<=tot;i++)for(j=1;j<=tot;j++)Map[i][j]=min(Map[i][j],Map[i][k]+Map[k][j]);//floyd预处理距离for(i=1;i<=N;i++)for(j=1;j<=M;j++){if(s[i][j]=='s')St=id[i][j];if(s[i][j]=='t')pos[v[0]+1]=id[i][j];if(s[i][j]>='A'&&s[i][j]<='Z')pos[s[i][j]-'A'+1]=id[i][j];}U=(1<<v[0])-1;V[0]=K;for(i=1;i<=U;i++){int tmp=0;for(j=1;j<=v[0];j++)if((i>>j-1)&1)tmp+=v[j];V[i]=tmp+K;if(V[i]<1)V[i]=1;}//预处理Vmemset(f,60,sizeof(f));for(i=1;i<=v[0];i++)f[1<<i-1][0][i]=Map[St][pos[i]]*K;f[0][0][v[0]+1]=Map[St][pos[v[0]+1]]*K;inf=f[0][0][0];for(j=0;j<U;j++)for(i=0;i<=U;i++){if(i&j)continue;//在这样的定义下,不能有交集for(x=1;x<=v[0]+1;x++){if(f[i][j][x]==inf||(x<=v[0]&&(!((i>>x-1)&1))))continue;for(y=1;y<=v[0];y++){if((i>>y-1)&1||(j>>y-1)&1)continue;if(f[i|(1<<y-1)][j][y]>f[i][j][x]+V[i]*Map[pos[x]][pos[y]])f[i|(1<<y-1)][j][y]=f[i][j][x]+V[i]*Map[pos[x]][pos[y]];}y=v[0]+1;if(f[i][j][y]>f[i][j][x]+V[i]*Map[pos[x]][pos[y]])f[i][j][y]=f[i][j][x]+V[i]*Map[pos[x]][pos[y]];}for(x=i;x;x=x-1&i)f[i^x][j|x][v[0]+1]=min(f[i^x][j|x][v[0]+1],f[i][j][v[0]+1]);//枚举子集}printf("%d",f[0][U][v[0]+1]);
}

蒜头君救人 状压DP相关推荐

  1. UVa 11825 (状压DP) Hackers' Crackdown

    这是我做状压DP的第一道题,状压里面都是用位运算来完成的,只要耐下心来弄明白每次位运算的含义,还是容易理解的. 题意: 有编号为0~n-1的n台服务器,每台都运行着n中服务,每台服务器还和若干台其他服 ...

  2. 「CTSC2017」吉夫特(Gift) (Lucas定理,状压DP)

    题面 链接 简单的题目,既是礼物,也是毒药. B 君设计了一道简单的题目,准备作为 gift 送给大家. 输入一个长度为 n n n 的数列 a 1 , a 2 , ⋯ , a n a_1, a_2, ...

  3. POJ 1038 Bugs Integrated Inc (复杂的状压DP)

    \(POJ~1038~~*Bugs~Integrated~Inc:\) (复杂的状压DP) \(solution:\) 很纠结的一道题目,写了大半天,就想练练手,结果这手生的.其实根据之前那道炮兵阵地 ...

  4. codeforces 8C. Looking for Order 状压dp

    题目链接 给n个物品的坐标, 和一个包裹的位置, 包裹不能移动. 每次最多可以拿两个物品, 然后将它们放到包里, 求将所有物品放到包里所需走的最小路程. 直接状压dp就好了. #include < ...

  5. UVA10296 Jogging Trails(中国邮递员问题)(欧拉回路、一般图最大权匹配 / 状压DP)

    整理的算法模板合集: ACM模板 目录 思路 UVA10296 Jogging Trails 题目翻译: 给你n个点,m条无向边,每条边有一定的距离数值,构造成一个连通图.问从任意一点出发,遍历所有的 ...

  6. POJ 2411 Mondriaan‘s Dream(最清楚好懂的状压DP讲解)(连通性状态压缩DP)

    poj 2411 Mondriaan's Dream(最清晰的状压DP解析) 闫氏DP大法好 我们这里是一列一列地来,因为是一个棋盘性的状态压缩DP,从哪个方向都一样 摆放的小方格总方案数 等价于 横 ...

  7. 【每日DP】day2、P1879 [USACO06NOV]Corn Fields G玉米地(状压DP模板题)难度⭐⭐⭐★

    昨天的每日DP我还在写01背包,今天就到状压DP了,真刺激. P1879 [USACO06NOV]Corn Fields G 题目链接 输入 2 3 1 1 1 0 1 0 输出 9 一道简单的状压D ...

  8. hdu 4778 Gems Fight! 状压dp

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

  9. 【洛谷 P1896】[SCOI2005]互不侵犯(状压dp)

    题目链接 题意:在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子. 这是道状压\(DP\)好题啊.. ...

最新文章

  1. 厉害!重庆参加马拉松赛人数7年翻10倍,今年区县马拉松赛事将大增
  2. 自学python找工作工资-大四应届毕业生,学了两个月Python,找工作感觉好难啊?...
  3. Linux-xargs命令
  4. nginx源码分析--使用GDB调试
  5. day11-元组与字典
  6. LAB Color Space
  7. java工程师面试题:如何判断链表有环?
  8. SQL Server 2005利用分区对海量数据的处理
  9. Fedora 33 配置Samba 服务器
  10. Android手机游戏开发入门教程
  11. 一 . 暴力破解与实用性优先
  12. spilt的用法小结
  13. 20221115使用google文档翻译SRT格式的字幕
  14. matlab独立t样本检验,matlab与单样本t检验
  15. 医学影像设备学_【技士/师证考试宝典】第四篇 医学影像设备学CR 11
  16. smb1文件共享不安全不能连接文件共享
  17. cpu 占用过高排查
  18. matlab近红外光谱曲线,Matlab关于偏最小二乘法应用于近红外光谱分析的问题
  19. AST反混淆实战-经典ob混淆
  20. ​草莓熊python绘图(春节版,圣诞倒数雪花版)附源代码

热门文章

  1. B. Kevin and Permutation codeforces1754B
  2. 《康熙大帝》和《雍正皇帝》EXE电子书
  3. 第十五天学习HTML、CSS
  4. (文末送书)一文读懂 Web 安全
  5. Gen8 ESXi 6.5 硬盘RDM 直通
  6. STM32 |显示:API is not found, corresponding pack is missing or not selected
  7. Persistence 与HibernatePersistence详解
  8. 十天让你网站ip流量从十增至一万
  9. python创建虚拟环境报错_python 创建虚拟环境时报错OSError, setuptools下载失败
  10. OwnCloud搭建自己的私有云盘