蒜头君救人 状压DP
来源:互联网 发布:导弹升级数据 编辑:程序博客网 时间:2024/05/15 03:08
蒜头君救人
题目描述
蒜头君是一个乐于助人的好孩子,这天他所在的乡村发生了洪水,有多名村民被困于孤岛上,于是蒜头君决定去背他们离开困境,假设蒜头君所在的村子是
n×m 的网格,网格中.号代表平地,#号代表该地已被洪水淹没,A、B……等大写字母表示该地有村民被困,s代表蒜头君的起点,t代表蒜头君的终点。蒜头君的初始速度为 k 秒一格,他每次可以向上下左右 4 个方向中的一个移动 1 格。在背上一个村民后,他的速度可能会降低,也可能会加快,但他的速度不能快于 1 秒每格,那么蒜头君想知道,他最快需要多长时间将所有村民救出?
注意:不能在终点以外的地方放下村民;可以同时背多个村民。
输入格式
第一行 3 个正整数
n,m(1≤n,m≤10),k ,分别表示村庄长度、宽度、蒜头君初始速度。接下来
n 行,每行一个长度为m 的字符串,表示村庄的地形,字符串意义如上所述。接下来若干行,每行一个大写字母、一个整数,表示该编号的村民会使
k 增加 / 减少多少。行数等同于地形中大写字母的个数。大写字母按字典序,即A、B、C的顺序排列,保证前后两行的字母是连续的,村民个数小于等于 10。
输出格式
输出 1 个整数,表示最小用时。
样例输入
4 4 2
s.##
..A#
.B##
…t
A -3
B 4
样例输出
17
数据规模这么小,不是搜索就是状压。
标程给出的是三进制状压DP,但是这样做使得位运算的优势不复存在了。所以时间复杂度其实也只是理性愉悦,提取某一位常数很大。而且也增加了编程复杂度。
事实上二进制状压DP是可以的,并不会达到
定义状态
上述两式分别表示到一个地方接村民、在终点放村民。如果不用记忆化搜索的形式,注意循环顺序。
那么为什么跑得很快呢?因为在这样的定义下,
代码:
#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; }//预处理V memset(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
- 蒜头君救人
- 蒜头君的树
- 蒜头君吃桃子
- 蒜头君打老鼠
- 蒜头君的树
- 蒜头君的坐骑
- 蒜头君的兔子
- 蒜头君的排序
- 计蒜课 蒜头君走迷宫
- 计蒜客 蒜头君学英语
- 蒜头君的玩具娃娃
- java 蓝桥杯 蒜头跳木桩(dp入门方式之一)
- 蒜头君开公司【全排列】
- 计蒜客 蒜头君的随机数,造房子
- 蒜头君学代数(二分)
- 基础算法之“蒜头君采摘苹果”
- 蒜头君学英语--set()练习
- 谷歌大脑负责人:深度学习需要至少十万个样本
- 安装golang项目的 GVM
- System.arraycopy的详解以及应用场景
- mysql(2)-bin-log
- 秘密武器亮相京东JDD,FaaS全新概念震动金融圈
- 蒜头君救人 状压DP
- 网站策划注意事项
- linux kernel list head study
- php 常用设计模式
- linux 部署静态资源
- spring mvc简单项目示例
- 深入聊聊微服务架构的身份认证问题
- Java研发技术成长路线
- MySQL数据类型--decimal