蒜头君救人

蒜头君是一个乐于助人的好孩子,这天他所在的乡村发生了洪水,有多名村民被困于孤岛上,于是蒜头君决定去背他们离开困境,假设蒜头君所在的村子是 n imes 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 51n,m5,村民个数为 11;

对于 50% 的数据,满足 1le n,mle51n,m5,村民个数小于等于 55;

对于 100% 的数据,满足 1le n,mle101n,m10,村民个数小于等于 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 }
原文地址:https://www.cnblogs.com/Y-E-T-I/p/7260427.html