[状压dp][spfa] Jzoj P3737 挖宝藏

Description

 

 

题解

  • 我们可以发现宝藏数最多只会有9个,显然可以状压
  • 而且数据这么小,就可以愉快
  • 考虑dp,设f[i][j][k][s]表示在第i层(i,j)宝藏集合的状态为s
  • 状态转移方程就是f[i][j][k][s]=min(f[i][j][k][s1]+f[i][j][s-s1]-a[x][y])(s包含s1)
  • 还有向四个方向拓展,可以用spfa松弛
  • 对于换层操作,我们在所到层的同一位置f[i-1][x][y][1]=f[i][x][y][mi[num[i]+1]-1]

 

代码

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 using namespace std;
 5 const int N=15,M=1<<12,dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};
 6 int h,n,m,l,r,ans=1e8,mi[M],a[N][N][N],f[N][N][N][M],num[N],d[N*N][3],b[N][N][3],bz[N][N];
 7 inline int read()
 8 {
 9     int s=0,w=1;
10        char ch=getchar();
11        while (ch<'0'||ch>'9'){ if(ch=='-') w=-1;ch=getchar(); }
12        while (ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
13        return s*w;
14 }
15 int main()
16 {
17     freopen("treasure.in","r",stdin),freopen("treasure.out","w",stdout);
18     freopen("data.in","r",stdin);
19     h=read(),n=read(),m=read();
20     mi[0]=1; for (register int i=1;i<=11;++i) mi[i]=mi[i-1]*2;
21     for (register int i=1;i<=h;++i) for (register int j=1;j<=n;++j) for (register int k=1;k<=m;k++)
22     {
23         a[i][j][k]=read();
24         for (register int l=0;l<mi[11];l++) f[i][j][k][l]=1e8;
25     }
26     for (register int i=1;i<=h;++i)
27     {
28         num[i]=read();
29         for (register int j=1;j<=num[i];++j) b[i][j][0]=read(),b[i][j][1]=read();
30     }
31     for (register int i=h;i>=1;i--)
32     {
33         for (register int x=1;x<=n;++x) for (register int y=1;y<=m;++y) f[i][x][y][mi[num[i]]]=f[i+1][x][y][mi[num[i+1]+1]-1]+a[i][x][y],f[i][x][y][0]=a[i][x][y];
34         for (register int j=1;j<=num[i];++j) f[i][b[i][j][0]][b[i][j][1]][mi[j-1]]=a[i][b[i][j][0]][b[i][j][1]];
35         for (register int s=1;s<mi[num[i]+1];s++)
36             for (register int x=1;x<=n;++x) for (register int y=1;y<=m;++y)
37             {
38                 for (register int s1=1;s1<=s;s1++) if ((s&s1)==s1) if (f[i][x][y][s1]+f[i][x][y][s-s1]-a[i][x][y]<f[i][x][y][s]) f[i][x][y][s]=f[i][x][y][s1]+f[i][x][y][s-s1]-a[i][x][y];
39                 memset(bz,0,sizeof(bz)),d[1][0]=x,d[1][1]=y,l=0,r=1;
40                 while (l<r)
41                 {
42                     l++;
43                     for (register int k=0;k<4;k++)
44                     {
45                         register int xx=d[l][0]+dx[k],yy=d[l][1]+dy[k];
46                         if (xx>0&&xx<=n&&yy>0&&yy<=m&&f[i][xx][yy][s]>f[i][d[l][0]][d[l][1]][s]+a[i][xx][yy])
47                         {
48                             f[i][xx][yy][s]=f[i][d[l][0]][d[l][1]][s]+a[i][xx][yy];
49                             if (!bz[xx][yy]) bz[xx][yy]=1,d[++r][0]=xx,d[r][1]=yy;
50                         }
51                     }
52                     bz[d[l][0]][d[l][1]]=0;
53                 }
54             }
55     }
56     for (register int i=1;i<=n;++i) for (register int j=1;j<=m;++j) ans=min(ans,f[1][i][j][mi[num[1]+1]-1]);
57     printf("%d",ans);
58 }

 

posted @ 2019-08-10 19:54  BEYang_Z  阅读(182)  评论(0编辑  收藏  举报