可以发现,直接做spfa会比较难做。
我们考虑把一层一层的做。
首先有一个很显然的结论:一层的挖过得洞一定是一棵树。
单层的话,很容易想到状压DP。
肯定要DP每层的每个节点覆盖宝藏的情况且当前这个节点被挖过。
那么我们设g[i,j,s]表示点的坐标为(i,j)覆盖宝藏的情况为s。
为了合并s,我们肯定要先枚举s。
然后g[i,j,s]=min(g[i,j,s’]+g[i],j,s^s’-a[p][i][j]),s’≠∅
但是这个只是在合并自己的情况。
那么我们还需要更新相邻的值。
g[x+1,y,s]=min(g[x,y,s]+a[p][x+1][y])
g[x-1,y,s]=min(g[x,y,s]+a[p][x-1][y])
g[x,y+1,s]=min(g[x,y,s]+a[p][x][y+1])
g[x,y-1,s]=min(g[x,y,s]+a[p][x][y-1])
然后这个地方用spfa来优化。
这个东西相当于转移的时候不考虑是否覆盖宝藏,而是延伸这个树的枝叶(不会形成环,因为是最短路,所以是个树)
然后枝叶拓展完之后再向上面那样把两个不相交的非空子集合并。
这样就可以把一层给做完了。
然后每个点在向上一层开一个洞(从下往上做),在上一层开一个超级宝藏(就是说要进去二进制状态),来表示下面层的值。
假设1集合是超级宝藏,那么 g[x][y][1]=f[x][y][2k[i+1]+1−1] ,很显然要滚动,所以拿了个f出来。然后如果在新的这层(x,y)有宝藏在更新 g[x][y][2?] 注意:此时不要加入超级宝藏的值。
最后答案是 g[x][y][2k[1]+1−1]
#include
#include
#include
#include
#include
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--)
using namespace std;
const int maxn=15;
typedef long long ll;
ll i,j,l,t,n,m,ans,h,p,x,y,s,xx,yy,ss;
ll a[15][15][15],k[15];
ll g[15][15][2049],f[15][15][2049],er[15],head,tail,bz[15][15][15];
ll fang[4][2]={0,1,0,-1,1,0,-1,0};
int data[100007][2];
bool az[15][15];
int main(){
freopen("treasure.in","r",stdin);
freopen("treasure.out","w",stdout);
// freopen("fan.in","r",stdin);
scanf("%d%d%d",&h,&n,&m);
er[0]=1;fo(i,1,10)er[i]=er[i-1]*2;
fo(i,1,h*n){
fo(j,1,m)
scanf("%d",&a[(i-1)/n+1][(i-1)%n+1][j]);
}
fo(i,1,h){
scanf("%d",&k[i]);
fo(j,1,k[i]){
scanf("%d%d",&x,&y);
bz[i][x][y]=j;
}
}
fod(p,h,1){
memcpy(f,g,sizeof(f));memset(g,127/2,sizeof(g));
fo(i,1,n){
fo(j,1,m){
g[i][j][1]=f[i][j][er[k[p+1]+1]-1]+a[p][i][j];
if(bz[p][i][j])g[i][j][er[bz[p][i][j]]]=a[p][i][j];
}
}
fo(s,1,er[k[p]+1]-1){
fo(i,1,n){
fo(j,1,m){
for(l=((s-1)&s);l;l=((l-1)&s)){
g[i][j][s]=min(g[i][j][s],g[i][j][s^l]+g[i][j][l]-a[p][i][j]);
}
}
}
head=0;tail=0;
fo(i,1,n)fo(j,1,m){
data[++tail][0]=i,data[tail][1]=j;az[i][j]=1;
}
while(head
xx=data[++head][0],yy=data[head][1];
fo(i,0,3){
x=xx+fang[i][0],y=yy+fang[i][1];
if(x<1||x>n||y<1||y>m)continue;
if(g[xx][yy][s]+a[p][x][y]
g[x][y][s]=g[xx][yy][s]+a[p][x][y];
if(!az[x][y]){
data[++tail][0]=x,data[tail][1]=y;
az[x][y]=1;
}
}
}
az[xx][yy]=0;
}
}
}
ans=0x7fffffff;
fo(i,1,n)fo(j,1,m)ans=min(g[i][j][er[k[1]+1]-1],ans);
printf("%lld\n",ans);
}