题目大意
![这里写图片描述](https://img-blog.csdn.net/20170318155156054?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2h1bmtpdGxhdQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
解题思路
每层单独考虑,就是平面图的最小生成树,斯坦纳树。设F[i][j][s]表示当前在(i,j)目标点的选取情况为s的最小花费,观察可知当前状态可以由邻近节点走一步得来,也可以由当前节点s的两个子状态得来,注意减去重复的当前点的花费。我们可以枚举s,先更新所有点s的答案,再通过spfa更新其他点的答案。
对于多层,考虑先把下一层解决,把下一层当作一个目标点加在当前层上,每个点都要这样做,这样就可以解决从当前层走到最后的花费,问题就可以解决了。
code
using namespace std;
int const Mxn=10,Mxa=1<<10,Mxsi=1e4,Inf=1e9;
int H,N,M,A[Mxn+9][Mxn+9][Mxn+9],F[Mxn+9][Mxn+9][Mxa+9],
B[Mxn+9][Mxn+9][2],Q[Mxsi+9][2],Inq[Mxn+9][Mxn+9],K[Mxn+9],
W[4][2]={{-1,0},{0,-1},{0,1},{1,0}},G[Mxn+9][Mxn+9];
int main(){
//freopen("treasure.in","r",stdin);
//freopen("treasure.out","w ",stdout);
freopen("d.in","r",stdin);
freopen("d.out","w ",stdout);
scanf("%d%d%d",&H,&N,&M);
Fo(i,1,H)Fo(j,1,N)Fo(k,1,M)scanf("%d",&A[i][j][k]);
//Fo(j,1,N)Fo(k,1,M)Fo(l,1,Mxa)F[j][k][l]=Inf;
Fo(i,1,H){
scanf("%d",&K[i]);
Fo(j,1,K[i])scanf("%d%d",&B[i][j][0],&B[i][j][1]);
}
Fd(i,H,1){
K[i]++;int Mxs=(1<<K[i])-1;
Fo(j,1,N)Fo(k,1,M){
F[j][k][0]=A[i][j][k];
Fo(l,1,Mxs)F[j][k][l]=Inf;
F[j][k][1<<(K[i]-1)]=G[j][k]+A[i][j][k];
}
Fo(j,1,K[i]-1)F[B[i][j][0]][B[i][j][1]][1<<(j-1)]=A[i][B[i][j][0]][B[i][j][1]];
//Fo(j,1,K)scanf("%d%d",&B[j][0],&B[j][1]),F[B[j][0]][B[j][1]][1]=F[B[j][0]][B[j][1]][0];
Fo(s,1,Mxs){
int He=0,Ti=0;
for(int ss=s;ss;ss=(ss-1)&s)Fo(j,1,N)Fo(k,1,M)
F[j][k][s]=Min(F[j][k][s],F[j][k][ss]+F[j][k][s-ss]-A[i][j][k]);
//Fo(j,1,K)F[B[j][0]][B[j][1]][s]=F[B[j][0]][B[j][1]][s^(1<<(j-1))];
Fo(j,1,N)Fo(k,1,M)Q[++Ti][0]=j,Q[Ti][1]=k,Inq[j][k]=1;
while(He!=Ti){
int X=Q[++He][0],Y=Q[He][1];
Fo(l,0,3)if(F[X+W[l][0]][Y+W[l][1]][s]>F[X][Y][s]+A[i][X+W[l][0]][Y+W[l][1]]){
F[X+W[l][0]][Y+W[l][1]][s]=F[X][Y][s]+A[i][X+W[l][0]][Y+W[l][1]];
if(!Inq[X+W[l][0]][Y+W[l][1]]){
Inq[X+W[l][0]][Y+W[l][1]]=1;
Q[++Ti][0]=X+W[l][0];
Q[Ti][1]=Y+W[l][1];
if((Q[Ti][0]<1)||(Q[Ti][1]<1)){
int bb;
bb++;
}
}
}
Inq[X][Y]=0;
}
}
Fo(j,1,N)Fo(k,1,M)G[j][k]=F[j][k][Mxs];
}
int Ans=Inf;
Fo(j,1,N)Fo(k,1,M)Ans=Min(Ans,G[j][k]);
printf("%d",Ans);
return 0;
}