Description
Solution
这题是关于斯坦纳树的;
先来考虑一下当h=1的情况:
我们发现,最后的答案构建出来一定是一颗树,
那么就设DP方程:
fx,y,S
表示以x,y这个点为根的树联通了集合S的点,
那么它可以由以下的数转移过来:(a为代价)
min(fx−1,y,S,fx+1,y,S,fx,y−1,S,fx,y+1,S,)
min{fx,y,S′+fx,y,S−S′−ax,y(S′∈S)}
从小到大枚举S,对于每一个位置,更新完以后用SPFA更新其它点,
当 h>1 时,可以在压缩状态时多压缩一位,表示有没有从上一层转移过来
复杂度:枚举子集的复杂度是:
S=∑ji=12j∗Cij
O(hnm∗(S+SPFA))
Code
标称SB的用了两个数组而不是多用一个二进制QAQ,辣鸡
#include <cstdio>
#include <cstdlib>
#include <cstring>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define OK(q,w) ((q)>0&&(w)>0&&(q)<=n&&(w)<=m)
#define min(q,w) ((q)<(w)?(q):(w))
using namespace std;
const int N=12,M=1025;
int read(int &n)
{
char ch=' ';int q=0,w=1;
for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
if(ch=='-')w=-1,ch=getchar();
for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int m,n,h,m1,ans,FAIL;
int a[N][N][N];
int b[N][N];
int er[11];
int f[N][N][M][2],F[N][N];
int d[M*M][3];
bool z[N][N][2];
int FX[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
void SPFA(int e,int I)
{
int S=1,T=0;
fo(i,1,n)fo(j,1,m)fo(k,0,1)if(f[i][j][e][k]<FAIL)d[++T][0]=i,d[T][1]=j,d[T][2]=k,z[i][j][k]=1;
int q,w,t;
while(S<=T)
{
q=d[S][0],w=d[S][1],t=d[S][2];
fo(k,0,3)if(OK(q+FX[k][0],w+FX[k][1]))
{
int q1=q+FX[k][0],w1=w+FX[k][1];
if(f[q1][w1][e][t]>f[q][w][e][t]+a[I][q1][w1])
{
f[q1][w1][e][t]=f[q][w][e][t]+a[I][q1][w1];
if(!z[q1][w1][t])z[q1][w1][t]=1,d[++T][0]=q1,d[T][1]=w1,d[T][2]=t;
}
if(!t)if(f[q1][w1][e][1]>f[q][w][e][t]+a[I][q1][w1]+F[q1][w1])
{
f[q1][w1][e][1]=f[q][w][e][t]+a[I][q1][w1]+F[q1][w1];
if(!z[q1][w1][1])z[q1][w1][t]=1,d[++T][0]=q1,d[T][1]=w1,d[T][2]=1;
}
}
z[q][w][t]=0;
S++;
}
}
void ss(int q,int w,int x,int y,int e,int I)
{
f[x][y][e][0]=min(f[x][y][e][0],f[x][y][w][0]+f[x][y][e-w][0]-a[I][x][y]);
f[x][y][e][1]=min(f[x][y][e][1],f[x][y][w][1]+f[x][y][e-w][0]-a[I][x][y]);
f[x][y][e][1]=min(f[x][y][e][1],f[x][y][w][0]+f[x][y][e-w][1]-a[I][x][y]);
fo(i,q,m1)if(er[i]&e)ss(i+1,w+er[i],x,y,e,I);
}
int main()
{
freopen("treasure.in","r",stdin);
freopen("treasure.out","w",stdout);
er[1]=1;fo(i,2,10)er[i]=er[i-1]<<1;
int q,w,e;
read(h),read(n),read(m);
fo(i,1,h)fo(j,1,n)fo(k,1,m)read(a[i][j][k]);
fo(I,1,h)
{
fo(i,1,n)fo(j,1,m)b[i][j]=0;
read(m1);
fo(i,1,m1)
{
read(q),read(w);
b[q][w]=er[i];
}
memset(f,60,sizeof(f));
FAIL=f[0][0][0][0];
fo(i,1,n)fo(j,1,m)f[i][j][b[i][j]][1]=F[i][j]+a[I][i][j],f[i][j][b[i][j]][0]=a[I][i][j];
fo(k,0,er[m1+1]-1)
{
fo(i,1,n)fo(j,1,m)ss(1,0,i,j,k,I);
SPFA(k,I);
}
fo(i,1,n)fo(j,1,m)F[i][j]=f[i][j][er[m1+1]-1][1];
}
ans=1e9;
fo(i,1,n)fo(j,1,m)ans=min(ans,F[i][j]);
printf("%d\n",ans);
return 0;
}