bzoj 1556 墓地秘密 —— 状压DP

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1556

预处理出两个障碍四个方向之间的距离(转弯次数),就可以状压DP了;

但预处理很麻烦...参考了TJ...:https://blog.csdn.net/senyelicone/article/details/56668048

用 spfa ,记录当前位置带一个朝向,然后转移时判断一下如果朝向不同就+1;

最后再从起点出发同样预处理一下,作为初始状态即可;

注意读入的地图上的 '#' 不仅是机关石,还有墙...所以不能忽略。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int const maxn=105,maxm=20,inf=0x3f3f3f3f;
int n,m,T,f[1<<16][maxm][5],dis[maxm][5][maxm][5],d[maxn][maxn][5];
int dx[5]={0,1,0,-1},dy[5]={1,0,-1,0},xx[maxm],yy[maxm],sx,sy,ans;
bool vis[maxn][maxn],roc[maxn][maxn];
queue<pair<int,int> >q;
bool ck(int x,int y){return x>0&&y>0&&x<=n&&y<=m;}
void spfa(int nw,int x,int y,int dr)
{
    if(roc[x][y]||!ck(x,y))return;
    while(q.size())q.pop();
    memset(d,0x3f,sizeof d);
    q.push(make_pair(x,y)); vis[x][y]=1;
    for(int k=0;k<4;k++)d[x][y][k]=0;
    while(q.size())
    {
        int nx=q.front().first,ny=q.front().second; q.pop(); vis[nx][ny]=0;
        for(int i=0;i<4;i++)
        {
            int tx=nx+dx[i],ty=ny+dy[i];
            if(roc[tx][ty]||!ck(tx,ty))continue;//
            for(int j=0;j<4;j++)
                if(d[tx][ty][j]>d[nx][ny][i]+(i!=j))
                {
                    d[tx][ty][j]=d[nx][ny][i]+(i!=j);
                    if(!vis[tx][ty])vis[tx][ty]=1,q.push(make_pair(tx,ty));
                }
        }
    }
    for(int i=1;i<=T;i++)
        for(int j=0;j<4;j++)//从j撞击xi,yi 
        {
            int tx=xx[i]+dx[j],ty=yy[i]+dy[j],tmp=inf;
            for(int k=0;k<4;k++)tmp=min(tmp,d[tx][ty][k]+(tx+dx[k]!=xx[i]||ty+dy[k]!=yy[i]));//反向
            dis[nw][dr][i][j]=tmp; 
        }
}
int main()
{
    scanf("%d%d%d",&n,&m,&T);
    char ch[maxn];
    for(int i=1;i<=n;i++)
    {
        cin>>ch;
        for(int j=0;j<m;j++)
            if(ch[j]=='#')roc[i][j+1]=1;
    }
    for(int i=1;i<=T;i++)
    {
        scanf("%d%d",&xx[i],&yy[i]);
//        roc[x][y]=1;//'#'表示墙,不一定是机关石!!! 
    }
    for(int i=1;i<=T;i++)
        for(int j=0;j<4;j++)
            spfa(i,xx[i]+dx[j],yy[i]+dy[j],j);
    scanf("%d%d",&sx,&sy);
    spfa(T+1,sx,sy,4);
    memset(f,0x3f,sizeof f); f[0][T+1][4]=0;
    int mx=(1<<T); ans=inf;
    for(int s=0;s<mx;s++)
      for(int i=1;i<=T+1;i++)
        for(int j=0;j<=4;j++)  if(f[s][i][j]!=inf)
          for(int k=1;k<=T;k++)
            for(int l=0;l<4;l++)
              f[s|(1<<(k-1))][k][l]=min(f[s|(1<<(k-1))][k][l],f[s][i][j]+dis[i][j][k][l]+1);
    for(int i=1;i<=T;i++)
        for(int j=0;j<4;j++)
            ans=min(ans,f[mx-1][i][j]);
    printf("%d\n",ans);
    return 0;
}

 

posted @ 2018-08-01 10:02  Zinn  阅读(172)  评论(0编辑  收藏  举报