zoukankan      html  css  js  c++  java
  • 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
    ",ans);
        return 0;
    }
  • 相关阅读:
    Unity 摄像机Clear Flags和Culling Mask属性用途详解
    Unity 坐标系
    Unity 模型导入导出
    Unity 序列化
    正确理解静态Static关键字
    Unity 中的协同程序
    Asp.Net中调用存储过程并返回输出参数
    php学习知识点
    Jauery 中Ajax的几种异步请求
    2014年12月21号面试
  • 原文地址:https://www.cnblogs.com/Zinn/p/9399643.html
Copyright © 2011-2022 走看看