[状压dp][spfa] Jzoj P3737 挖宝藏
题解
- 我们可以发现宝藏数最多只会有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 }