【NOI2014模拟7.11】【WC2008游览计划加强】挖宝藏

来源:互联网 发布:软件主管岗位职责 编辑:程序博客网 时间:2024/05/19 05:29

Description

这里写图片描述

Solution

可以发现,直接做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]+11],很显然要滚动,所以拿了个f出来。然后如果在新的这层(x,y)有宝藏在更新g[x][y][2?]注意:此时不要加入超级宝藏的值。
最后答案是g[x][y][2k[1]+11]

Code

#include<iostream>#include<stdio.h>#include<string.h>#include<algorithm>#include<math.h>#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<tail){                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[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);}
1 0