蒜头君救人

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

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

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

输入格式

第一行 33 个正整数 n,m,kn,m,k,分别表示村庄长度、宽度、蒜头君初始速度。

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

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

输出格式

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

数据规模

对于 10% 的数据,满足 1 \le n,m \le 51≤n,m≤5,村民个数为 11;

对于 50% 的数据,满足 1\le n,m\le51≤n,m≤5,村民个数小于等于 55;

对于 100% 的数据,满足 1\le n,m\le101≤n,m≤10,村民个数小于等于 1010。

样例输入

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

样例输出

17题解:dp首先是50分做法:定义f[2^num][2^num][x][y]第一维每一位若为 1 表示该村民正被蒜头君所背,第二维每一位若为1表示该村民已被放至安全地带,最后两维表示蒜头君当前所处位置。转移时分别考虑是否有村民,是否是终点就行了复杂度为O(4^num*n*m)100分:将一维和二维合起来,定义一个三进制数,0表示还没救,1表示背在身上,2表示已送达转移用记忆化搜索就行了,不用考虑转移顺序,但YZD大神直接dp,效率贼高在到终点时,不用枚举子集,直接考虑2种情况:1.把会减慢速度的人放下2.把所有人放下
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cstring>
  5 using namespace std;
  6 struct Node
  7 {
  8     int x,y,s;
  9 }q[2000001];
 10 int dx[5]={0,1,-1,0,0},dy[5]={0,0,0,1,-1};
 11 int peo[11],k,n,m,t,sp[11],pw[11];
 12 int f[60001][11][11];
 13 char a[11][11],s[11][11];
 14 int cal_spd(int x)
 15 {int p=0,ss=0,i;
 16 memset(peo,0,sizeof(peo));
 17     while (x)
 18     {
 19         p++;
 20         peo[p]=x%3;
 21         x/=3;
 22     }
 23     ss=k;
 24     for (i=1;i<=t;i++)
 25     {
 26         if (peo[i]==1)
 27         {
 28             ss+=sp[i];
 29         }
 30     }
 31     if (ss<1) ss=1;
 32     return ss;
 33 }
 34 int pick(int ss,int x,int y)
 35 {int i,po,p=0;
 36     for (i=1;i<=t;i++)
 37     if (a[x][y]==s[i][0])
 38     {
 39       po=i;break;
 40     }
 41     memset(peo,0,sizeof(peo));
 42     while (ss)
 43     {
 44         p++;
 45         peo[p]=ss%3;
 46         ss/=3;
 47     }
 48     for (i=1;i<=t;i++)
 49     if (peo[po]) return 0;
 50     peo[po]=1;
 51     for (i=t;i>=1;i--)
 52     ss=ss*3+peo[i];
 53     return ss;
 54 }
 55 int drop1(int ss,int x,int y)
 56 {int p=0,i;
 57     memset(peo,0,sizeof(peo));
 58     while (ss)
 59     {
 60         p++;
 61         peo[p]=ss%3;
 62         ss/=3;
 63     }
 64     for (i=1;i<=t;i++)
 65     if (peo[i]==1) peo[i]=2;
 66     for (i=t;i>=1;i--)
 67     ss=ss*3+peo[i];
 68     return ss;
 69 }
 70 int drop2(int ss,int x,int y)
 71 {int p=0,i;
 72     memset(peo,0,sizeof(peo));
 73     while (ss)
 74     {
 75         p++;
 76         peo[p]=ss%3;
 77         ss/=3;
 78     }
 79     for (i=1;i<=t;i++)
 80     if (peo[i]==1&&sp[i]>0) peo[i]=2;
 81     for (i=t;i>=1;i--)
 82     ss=ss*3+peo[i];
 83     return ss;
 84 }
 85 int main()
 86 {int i,j,xh,yh,xt,yt,head,tail;
 87     scanf("%d%d%d",&n,&m,&k);
 88     for (i=1;i<=n;i++)
 89     {
 90         scanf("%s",a[i]+1);
 91         for (j=1;j<=m;j++)
 92         if (a[i][j]==‘s‘) xh=i,yh=j;
 93         else if (a[i][j]==‘t‘) xt=i,yt=j;
 94         else
 95         if (a[i][j]>=‘A‘&&a[i][j]<=‘Z‘) t++;
 96     }
 97      for (i=1;i<=t;i++)
 98      {
 99          scanf("%s%d",s[i],&sp[i]);
100      }
101      pw[0]=1;
102      for (i=1;i<=t;i++)
103      pw[i]=pw[i-1]*3;
104      memset(f,127/3,sizeof(f));
105      f[0][xh][yh]=0;
106       q[1].x=xh;q[1].y=yh;q[1].s=0;
107       head=0;tail=1;
108       while (head<tail)
109       {
110            head++;
111            head%=2000000;
112              int spd=cal_spd(q[head].s);
113                int nx=q[head].x,ny=q[head].y;
114                for (i=1;i<=4;i++)
115                {
116                    int x=nx+dx[i],y=ny+dy[i];
117                    if (x>=1&&x<=n&&y>=1&&y<=m)
118                    {
119                        if (a[x][y]!=‘#‘&&f[q[head].s][x][y]>f[q[head].s][nx][ny]+spd)
120                        {
121                            f[q[head].s][x][y]=f[q[head].s][nx][ny]+spd;
122                            tail++;tail%=2000000;
123                            q[tail].s=q[head].s;q[tail].x=x;q[tail].y=y;
124                     }
125                     if (a[x][y]>=‘A‘&&a[x][y]<=‘Z‘)
126                     {
127                         int nxt=pick(q[head].s,x,y);
128                          if (f[nxt][x][y]>f[q[head].s][nx][ny]+spd)
129                          {
130                              f[nxt][x][y]=f[q[head].s][nx][ny]+spd;
131                              tail++;tail%=2000000;
132                              q[tail].s=nxt;q[tail].x=x;q[tail].y=y;
133                          }
134                     }
135                     if (a[x][y]==‘t‘)
136                     {
137                         int nxt1=drop1(q[head].s,x,y);
138                         int nxt2=drop2(q[head].s,x,y);
139                         if (f[nxt1][x][y]>f[q[head].s][x][y])
140                         {
141                             f[nxt1][x][y]=f[q[head].s][x][y];
142                             tail++;tail%=2000000;
143                             q[tail].s=nxt1;q[tail].x=x;q[tail].y=y;
144                         }
145                         if (f[nxt2][x][y]>f[q[head].s][x][y])
146                         {
147                             f[nxt2][x][y]=f[q[head].s][x][y];
148                             tail++;tail%=2000000;
149                             q[tail].s=nxt2;q[tail].x=x;q[tail].y=y;
150                         }
151                     }
152                 }
153              }
154       }
155     cout<<f[pw[t]-1][xt][yt];
156 }
时间: 2024-10-10 14:06:03

蒜头君救人的相关文章

蒜头君打地鼠

蒜头君打地鼠 蒜头君最近迷上了打地鼠,但他发现同时出现在面板上的地鼠太多,于是他想改进一下他的锤子,于是他拿出了一款 k \times kk×k 大小的正方形锤子,但是遗憾的是,这个锤子只能斜着砸.如下图所示: 当 k=2k=2 时,若蒜头君敲击黑点,黑点和图中所有蓝色点将一并被敲到. 当 k=3k=3 时,锤子的图案如下所示: 1 - - * - - 2 - * * * - 3 * * x * * 4 - * * * - 5 - - * - - kk 取其他值时以此类推. 注意:蒜头君只能敲击

蒜头君的树

蒜头君的树 蒜头君有一棵有根树,树的每一边都有边权,蒜头君想知道任意两点间最短距离之和为多少.另外,由于各种原因,蒜头君的树的边的边权会发生若干次改变,蒜头君想让你告诉他,每一次改变后,任意两点间最短距离之和为多少? 输入格式 第一行一个正整数 nn,表示蒜头君的树上的结点个数. 接下来 n-1n?1 行,每行两个正整数 x_i,y_ix?i??,y?i??,x_ix?i?? 表示 i+1i+1 号结点的父亲结点的编号,保证其父结点编号小于自己编号.y_iy?i?? 表示 i+1i+1 号结点的

蒜头君的兔子

蒜头君的兔子 2017-09-03 题目描述 蒜头君的小伙伴在 第一年 送给他一对 一岁 的兔子,并告诉他:这种兔子 刚生下来时算 0 岁,到了 2 岁时就可以繁殖了,它在 2?10 岁时,每年会生下来一对兔子,这些兔子到了 2 岁也可以繁殖,但这些兔子在 10 岁那年生完仔后 不久就会死亡,蒜头君想知道,第 n 年兔子 产仔之后(第 n 年 10 岁的兔子此时已经死亡),他会有多少对兔子.结果对 1000000007 取模. 输入格式 共一行,一个正整数 n,表示蒜头君想知道第 nn 年的兔子

最长上升子序列——蒜头君的娃娃

蒜头君十分喜爱它的娃娃,经常会把它们摆成一列.蒜头君从左到右依次给他们编号为 11 到 NN,每个娃娃都有自己的萌值 T_iT?i??.现在蒜头君想从已经摆好的队列中,去除几个娃娃,使得剩余的队列满足以下条件: \displaystyle T_1 < ... < T_i > T_{i+1} > ... > T_K (1 \leq i \leq K)T?1??<...<T?i??>T?i+1??>...>T?K??(1≤i≤K) 现在已知队列中 N

蒜头君的坐骑

蒜头君有一只坐骑,人马. 一天,蒜头君骑着他的坐骑走上了一片 n \times mn×m 的大荒野,一开始时,蒜头君在 (1,1)(1,1) 点,他要前往 (n,m)(n,m) 点,蒜头君的人马每次可以向右或向下移动一格.然而这片荒野并不平静,除了起点和终点外每个点都有一只怪物会袭击蒜头君. 然而蒜头君的人马强大无比,它会先对怪物造成等同于它攻击力的伤害,然后蒜头君才会受到怪物的攻击,伤害等同于怪物的攻击力.然后人马再攻击怪物,怪物再攻击蒜头君,直至怪物死去,假设每个怪物具有相同的体力. 此外,

RMQ——蒜头君的玩具娃娃(区间范围最大值-区间范围最小值)

蒜头君有 N 个玩具娃娃,编号依次从 1 到 N,每个娃娃都有自己的高度值.蒜头君想考考聪明的你,蒜头君会有 Q 次询问,每次询问给定两个整数 A 和 B,求问编号 A 和编号 B 之间(包含编号 A 和编号 B),高度最大的娃娃和高度最小的娃娃差是多少. 输入格式 第一行输入两个正整数 N,Q(N≤50,000,Q≤200,000).代表 N 个玩具娃娃,以及蒜头君的 Q 次 询问. 接下来输入 N 行,每行输入一个正整数 h?i??(1≤h?i??≤1,000,000),表示第i 个玩具的高

61计蒜客 动态规划基础 蒜头君的城堡之旅

蒜国地域是一个 n 行 m 列的矩阵,下标均从 1 开始.蒜国有个美丽的城堡,在坐标 (n,m) 上,蒜头君在坐标 (1,1) 的位置上.蒜头君打算出发去城堡游玩,游玩结束后返回到起点.在出发去城堡的路上,蒜头君只会选择往下或者往右走,而在返回的路上,蒜头君只会选择往上或者往左走,每次只能走一格.已知每个格子上都有一定数量的蒜味可乐,每个格子至多经过一次. 现在蒜头君请你来帮他计算一下,如何计划来回行程,可以收集到最多的蒜味可乐. 输入格式 第一行输入两个整数 n,m(1≤n,m≤50),表示蒜

动态规划|蒜头君跳木桩-最长下降子序列

蒜头君跳木桩 蒜头君面前有一排?nn?个木桩,木桩的高度分别是h_1,h_2,h_3\cdots h_nh1?,h2?,h3??hn?.蒜头第一步可以跳到任意一个木桩,接下来的每一步蒜头不能往回跳只能往前跳,并且跳下一个木桩的高度?不大于?当前木桩.蒜头君希望能踩到尽量多的木桩,请你帮蒜头计算,最多能踩到多少个木桩. 输入格式 第一行输入一个整数?nn?代表木桩个数.第二行输入?nn?个整数?h_1,h_2,h_3\cdots h_nh1?,h2?,h3??hn?,分别代表?nn?个木桩的高度.

蒜头君的购物袋3-(完全背包)

问题描述 蒜头君去超市购物,他有一只容量为 V 的购物袋,同时他想买 nn 种物品,已知每种物品的体积 vi和重要度 pi .蒜头君想知道,怎么挑选物品放入购物袋中,可以使得买到的物品重要度之和最大,且物品体积和不超过购物袋的容量.注意超市中每种物品的数量无限多. 输入格式 第一行输入两个整数 n, V (1≤n≤1,000,1≤V≤10,000). 接下来输入 n 行,每行输入两个整数 vi和pi(1≤vi,pi≤10,000),分别表示第 i 种物品的体积和重要度. 输出格式 输出一行,输出