Hdu 4634 DP|最短路

首先,此题32M的空间决定不能开200*200*128*4的int型,不能太暴力。。
      还有,明显不能一小步一小步,而要一条一条走。
      读入图的外边界不是障碍物,所以会滑出去,而不能停在那里继续走。
      但是经过E且从E出去(即最后一步)又是个例外。
方法一【28M左右】:
      每个点怎么走与之前到这个点的方向没有关系。
      如果是RDUL,接下来这步的方向就确定了
      如果是障碍物边上的点,可以向没有被障碍物挡住的任一边走,
      甚至可以怎么来的怎么回去。
     (可能为了拿把钥匙,当然绝大多数情况只是在浪费步数(那是之后的事),但是必须不能漏这个方向)
      因此,预处理出每个【可停留点】向四周到达的点,这条路上的钥匙,这条路上是否有出口。
      最后从S开始求最短路即可(因为RDUL型不算步数,权值有0有1)
      最短路核心部分//CLEAR Qx、Qy和Qs;
      Qx.push(sx);Qy.push(sy);Qs.push(0);
      dp[0][sx][sy]=0;
      while(!Qx.empty()){   
 int x=Qx.front(),y=Qy.front(),s=Qs.front();
          Qx.pop();Qy.pop();Qs.pop();
          for(int d=0;d<4;++d){
           【更新答案】如果加一条路可以更新答案(钥匙够了&&门走路上)就更新答案;
    【更新队列】如果可以更新路的另一端就更新,并加到队列中 (前提是路的另一端是个【图内点】)
   }
  }
      那。。。E算不算一个【可停留点】?
      不算,可停留点必须要满足一个性质——到可停留点和出可停留点不属于同一条路,
      即方向不同(右和右算相同,右和左、上、下算不同)
      不然,两条路一合,答案就更小了。。。
     (E是可以出的,当钥匙未满时)
      
      那么那些属于【可停留点】?
      比如说预处理向上方向时,这些均属于可停留点。(很容易漏的)
      1.读入图的外边界(但它们不属于【图内点】,求最短路更新队列时要注意)
      2.上一格是障碍物的点,且这格不是障碍物
      3.这格是R、D、L(注意没有U)


      好了,最后还有一个坑。。一条路上既有E也有钥匙,拿完钥匙再到出口还是
      到出口时后面还有未曾拿到过的钥匙。。。
      所以预处理时还要预处理这条路到出口前能拿到的钥匙。求最短路更新答案时用。


方法二【28M左右】:
      之前贴的方法二有误,8月3日中午13点更新代码

      到达RDUL模拟最终停在那里(要处理形成环的情况,永远走不完的情况)
      这样每条路的权值只有1了,最后广搜即可。
     
方法三【1M左右】:(照着标称打了一遍)
       最多只有9个【特殊点】,S+E+K
       预处理出d[9][4][9][4](对每个【特殊点】四种方向(前面的9 4)全图的bfs,
      取有用的记录到dp里(后面的9 4))
       d[i][k1][j][k2]代表从i点出发沿k1方向到达j点为k2方向时的最小步数
       再求dp[9][127][4]
       dp[i][j][k]从S点任一方向,k方向到i【特殊点】,钥匙状态为j至少用了几步
       最后从dp[][所有钥匙][]更新到答案里去


题外话:标程是有欠缺的,hdu在8月2日晚饭左右时间加强了数据,于是标程跪了。
  (题解里有原话——注意一个强制拐弯的格子如果强制方向的下一个格子是墙,那么它将永远卡住。)
  但标程却没有考虑,估计放错程序了。
 
给出一组数据
3 3
RKD
S#E
UKL
ans=1;

//方法一
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define N 205
using namespace std;
const int INF=0x3f3f3f3f;
struct str1{
    int k1,k2,p,ck;
};
int a[N][N];
char s[N];
str1 pre[N][N][4];
int dp[1<<7][N][N];
int n,m,sx,sy,ex,ey,tot,ma,ans;
queue<int> Qx,Qy,Qs;
void clear()
{   while (!Qx.empty()) Qx.pop();
    while (!Qy.empty()) Qy.pop();
    while (!Qs.empty()) Qs.pop();
}
bool minimize(int &p,int  q)
{   if(p<=q)return 0;
    p=q;
    return 1;
}
void prepare0();
void prepare1();
void prepare2();
void prepare3();
void bfs()
{       int tmp;
        ans=INF; memset(dp,0x3f,sizeof(dp));
        clear();
        Qx.push(sx);Qy.push(sy);Qs.push(0);
        dp[0][sx][sy]=0;
        while(!Qx.empty())
        {   int x=Qx.front(),y=Qy.front(),s=Qs.front();
            Qx.pop();Qy.pop();Qs.pop();
            for(int d=0;d<4;++d)
             {  if (a[x][y]>=-8&&a[x][y]<=-5&&a[x][y]+8!=d) continue;
                if (pre[x][y][d].p==-1) continue;
                if (a[x][y]>=-8&&a[x][y]<=-5)tmp=0;else tmp=1;
                int tx=pre[x][y][d].p/N,ty=pre[x][y][d].p%N,ts=s|pre[x][y][d].k1;
                if(pre[x][y][d].ck&&((s|pre[x][y][d].k2)==ma)) minimize(ans,dp[s][x][y]+tmp);
                if (tx<1||tx>n||ty<1||ty>m)continue;
                if(minimize(dp[ts][tx][ty],dp[s][x][y]+tmp))
                    {Qx.push(tx);Qy.push(ty);Qs.push(ts);}
             }

        }
        if(ans==INF)printf("-1\n");else printf("%d\n",ans);
}

void doit()
{   char c;
    tot=0;
    for (int i=0;i<=n+1;i++)
       for (int j=0;j<=m+1;j++)
            a[i][j]=-1;
    for (int i=1;i<=n;i++)
        {scanf("%s",s);
         for (int j=1;j<=m;j++)
                 {c=s[j-1];
                  if (c=='#') a[i][j]=-2;
                  if (c=='.') a[i][j]=-1;
                  if (c=='S') {a[i][j]=-3; sx=i;sy=j;}
                  if (c=='E') {a[i][j]=-4; ex=i;ey=j;}
                  if (c=='K') {a[i][j]=1<<tot;tot++;}
                  if (c=='L') a[i][j]=-8;
                  if (c=='R') a[i][j]=-7;
                  if (c=='U') a[i][j]=-6;
                  if (c=='D') a[i][j]=-5;
                 }
        }
    ma=1<<tot;
    ma--;
    memset(pre,255,sizeof(pre));
    int i,j;
    i=0;
    for (j=0;j<=m+1;j++)
        for (int t=0;t<4;t++)
        {pre[i][j][t].p=i*N+j;
         pre[i][j][t].k1=pre[i][j][t].k2=pre[i][j][t].ck=0;
        }
    i=n+1;
    for (j=0;j<=m+1;j++)
        for (int t=0;t<4;t++)
        {pre[i][j][t].p=i*N+j;
         pre[i][j][t].k1=pre[i][j][t].k2=pre[i][j][t].ck=0;
        }
    j=0;
    for (i=1;i<=n;i++)
        for (int t=0;t<4;t++)
        {pre[i][j][t].p=i*N+j;
         pre[i][j][t].k1=pre[i][j][t].k2=pre[i][j][t].ck=0;
        }
    j=m+1;
    for (i=1;i<=n;i++)
        for (int t=0;t<4;t++)
        {pre[i][j][t].p=i*N+j;
         pre[i][j][t].k1=pre[i][j][t].k2=pre[i][j][t].ck=0;
        }
    prepare0();
    prepare1();
    prepare2();
    prepare3();
    bfs();
}
int main()
{
    while (scanf("%d%d",&n,&m)!=EOF) doit();
    return 0;
}
void prepare0()
{   int t=0;
     for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++)
             if (a[i][j]!=-2)
             {  int tmp=a[i][j]>=0?a[i][j]:0;
                 if (a[i][j-1]==-2||a[i][j]==-5||a[i][j]==-7||a[i][j]==-6)
                    {pre[i][j][t].p=i*N+j;
                     pre[i][j][t].k1=tmp;
                     pre[i][j][t].k2=tmp;
                     pre[i][j][t].ck=(a[i][j]==-4);
                    }
                 else
                     {pre[i][j][t].p=pre[i][j-1][t].p;
                      pre[i][j][t].ck=pre[i][j-1][t].ck||(a[i][j]==-4);
                      pre[i][j][t].k1=pre[i][j-1][t].k1+tmp;
                      pre[i][j][t].k2=pre[i][j-1][t].k2+pre[i][j][t].ck*tmp;
                     }
             }

}
void prepare1()
{   int t=1;
     for (int i=1;i<=n;i++)
        for (int j=m;j>=1;j--)
             if (a[i][j]!=-2)
             {  int tmp=a[i][j]>=0?a[i][j]:0;
                 if (a[i][j+1]==-2||a[i][j]==-5||a[i][j]==-8||a[i][j]==-6)
                    {pre[i][j][t].p=i*N+j;
                     pre[i][j][t].k1=tmp;
                     pre[i][j][t].k2=tmp;
                     pre[i][j][t].ck=(a[i][j]==-4);
                    }
                 else
                     {pre[i][j][t].p=pre[i][j+1][t].p;
                      pre[i][j][t].ck=pre[i][j+1][t].ck||(a[i][j]==-4);
                      pre[i][j][t].k1=pre[i][j+1][t].k1+tmp;
                      pre[i][j][t].k2=pre[i][j+1][t].k2+pre[i][j][t].ck*tmp;
                     }
             }
    }
void prepare2()
{   int t=2;
     for (int j=1;j<=m;j++)
        for (int i=1;i<=n;i++)
             if (a[i][j]!=-2)
             {  int tmp=a[i][j]>=0?a[i][j]:0;
                 if (a[i-1][j]==-2||a[i][j]==-8||a[i][j]==-7||a[i][j]==-5)
                    {pre[i][j][t].p=i*N+j;
                     pre[i][j][t].k1=tmp;
                     pre[i][j][t].k2=tmp;
                     pre[i][j][t].ck=(a[i][j]==-4);
                    }
                 else
                     {pre[i][j][t].p=pre[i-1][j][t].p;
                      pre[i][j][t].ck=pre[i-1][j][t].ck||(a[i][j]==-4);
                      pre[i][j][t].k1=pre[i-1][j][t].k1+tmp;
                      pre[i][j][t].k2=pre[i-1][j][t].k2+pre[i][j][t].ck*tmp;
                     }
             }
}
void prepare3()
{    int t=3;
     for (int j=1;j<=m;j++)
        for (int i=n;i>=1;i--)
             if (a[i][j]!=-2)
             {  int tmp=a[i][j]>=0?a[i][j]:0;
                 if (a[i+1][j]==-2||a[i][j]==-8||a[i][j]==-7||a[i][j]==-6)
                    {pre[i][j][t].p=i*N+j;
                     pre[i][j][t].k1=tmp;
                     pre[i][j][t].k2=tmp;
                     pre[i][j][t].ck=(a[i][j]==-4);
                    }
                 else
                     {pre[i][j][t].p=pre[i+1][j][t].p;
                      pre[i][j][t].ck=pre[i+1][j][t].ck||(a[i][j]==-4);
                      pre[i][j][t].k1=pre[i+1][j][t].k1+tmp;
                      pre[i][j][t].k2=pre[i+1][j][t].k2+pre[i][j][t].ck*tmp;
                     }
             }
}


//方法二
#include <iostream>
#include <numeric>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <queue>
#include <vector>
#pragma comment(linker,"/STACK:1024000000,1024000000")
using namespace std;
const int INF = 0x3f3f3f3f;
char Map[205][205];
int S[205][205],D[4][205][205],W[4][205][205],E[4][205][205],SE[4][205][205],dir[4][2]={0,-1,-1,0,1,0,0,1};
int dp[1<<7][205][205];
template<typename X>inline bool minimize(X&p,X q){if(p<=q)return 0;p=q;return 1;}
template<typename X>inline bool maximize(X&p,X q){if(p>=q)return 0;p=q;return 1;}
int check(int x,int y,int d){
    if(Map[x][y]=='L')return 0;
    if(Map[x][y]=='U')return 1;
    if(Map[x][y]=='D')return 2;
    if(Map[x][y]=='R')return 3;
    return d;
}
void dfs(int x,int y,int d){
    if(D[d][x][y])return;
    D[d][x][y]=-(x*205+y);
    W[d][x][y]|=S[x][y];
    int tx=x+dir[d][0],ty=y+dir[d][1],td=check(tx,ty,d);
    if(Map[tx][ty]=='*'){D[d][x][y]=tx*205+ty;return;}
    if(Map[tx][ty]=='#'){D[d][x][y]= x*205+ y;return;}
    dfs(tx,ty,td);
    D[d][x][y] = D[td][tx][ty];
    W[d][x][y]|= W[td][tx][ty];
    E[d][x][y]|= E[td][tx][ty];
    if(E[d][x][y])SE[d][x][y]|=S[x][y];
    if(D[d][x][y]==-(x*205+y)){
        D[d][x][y]=x*205+y;SE[d][x][y]=W[d][x][y];
        while(tx!=x||ty!=y||td!=d){
            D[td][tx][ty]=tx*205+ty;
            W[td][tx][ty]=W[d][x][y];
            E[td][tx][ty]=E[d][x][y];
            SE[td][tx][ty]=SE[d][x][y];
            tx+=dir[td][0];ty+=dir[td][1];
            td=check(tx,ty,td);
        }
    }
}
int main(){
    int N,M,sx,sy,ex,ey;
    while(~scanf("%d%d",&N,&M)){
        memset(Map,'*',sizeof(Map));
        memset(D,0,sizeof(D));
        memset(W,0,sizeof(W));
        memset(S,0,sizeof(S));
        memset(E,0,sizeof(E));
        memset(SE,0,sizeof(SE));
        memset(dp,0x3f,sizeof(dp));
        int tot=0;
        for(int i=1;i<=N;++i)
        for(int j=1;j<=M;++j){
            scanf(" %c",&Map[i][j]);
            if(Map[i][j]=='K')S[i][j]=1<<tot++;
            if(Map[i][j]=='S')sx=i,sy=j;
            if(Map[i][j]=='E')ex=i,ey=j,E[0][i][j]=E[1][i][j]=E[2][i][j]=E[3][i][j]=1;
        }
        int Maxs=(1<<tot)-1,ans=INF;
        for(int i=1;i<=N;++i)
        for(int j=1;j<=M;++j)if(Map[i][j]!='#')
        for(int d=0;d<4;++d)dfs(i,j,check(i,j,d));
        queue<int> Qx,Qy,Qs;
        Qx.push(sx);Qy.push(sy);Qs.push(0);
        dp[0][sx][sy]=0;
        while(!Qx.empty()){
            int x=Qx.front(),y=Qy.front(),s=Qs.front();
            Qx.pop();Qy.pop();Qs.pop();
            for(int d=0;d<4;++d)if (D[d][x][y]){
                int tx=D[d][x][y]/205,ty=D[d][x][y]%205,ts=s|W[d][x][y];
                if(ts==Maxs&&E[d][x][y]&&(s|SE[d][x][y])==Maxs)minimize(ans,dp[s][x][y]+1);
                if(Map[tx][ty]!='*'&&minimize(dp[ts][tx][ty],dp[s][x][y]+1)){
                    Qx.push(tx);
                    Qy.push(ty);
                    Qs.push(ts);
                }
            }
        }
        if(ans==INF)printf("-1\n");
        else printf("%d\n",ans);
    }
    return 0;
}

//方法三
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define N 205
using namespace std;
const int INF=0x3f3f3f3f;
char s[N][N];
int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};
int map[N][N][4];
int d[9][4][9][4];
int n,m,ex,ey,tot,ma;
queue<int> Qx,Qy,Qd;
int tr[9][2];
int dp[9][1<<7][4];
void clear()
{   while (!Qx.empty()) Qx.pop();
    while (!Qy.empty()) Qy.pop();
    while (!Qd.empty()) Qd.pop();
}

void bfs(int x,int y,int d)
{   memset(map,0x3f,sizeof(map));
    map[x][y][d]=0;
    int tx=x+dx[d],ty=y+dy[d],td=d;
    while (tx>=0&&tx<n&&ty>=0&&ty<m&&s[tx][ty]!='#')
         {if (map[tx][ty][td]<=0) break;
          map[tx][ty][td]=0;
               if (s[tx][ty]=='L'&&td!=3) td=3;
          else if (s[tx][ty]=='R'&&td!=1) td=1;
          else if (s[tx][ty]=='U'&&td!=2) td=2;
          else if (s[tx][ty]=='D'&&td!=0) td=0;
          else {tx+=dx[td];ty+=dy[td];}
         }
    if (tx>=0&&tx<n&&ty>=0&&ty<m&&s[tx][ty]=='#')
         {tx-=dx[td];ty-=dy[td];
         //标程漏了下一个if
 	  if (s[tx][ty]=='L'||s[tx][ty]=='R'||s[tx][ty]=='U'||s[tx][ty]=='D') return;
         }
    else return;
    clear();
    Qx.push(tx);Qy.push(ty);Qd.push(td);
    while(!Qx.empty())
    {   int nx=Qx.front(),ny=Qy.front(),nd=Qd.front(),dep=map[nx][ny][nd]+1;
        Qx.pop();Qy.pop();Qd.pop();
        for (int i=0;i<4;i++)if (i!=nd)
            {
                if (map[nx][ny][i]<=dep) continue;
                map[nx][ny][i]=dep;
                int tx=nx+dx[i],ty=ny+dy[i],td=i;
                while (tx>=0&&tx<n&&ty>=0&&ty<m&&s[tx][ty]!='#')
                         {if (map[tx][ty][td]<=dep) break;
                          map[tx][ty][td]=dep;
                               if (s[tx][ty]=='L'&&td!=3) td=3;
                          else if (s[tx][ty]=='R'&&td!=1) td=1;
                          else if (s[tx][ty]=='U'&&td!=2) td=2;
                          else if (s[tx][ty]=='D'&&td!=0) td=0;
                          else {tx+=dx[td];ty+=dy[td];}
                         }
                if (tx>=0&&tx<n&&ty>=0&&ty<m&&s[tx][ty]=='#')
                     {tx-=dx[td];ty-=dy[td];
 	 	 	//标程漏了下一个if
                      if (!(s[tx][ty]=='L'||s[tx][ty]=='R'||s[tx][ty]=='U'||s[tx][ty]=='D'))
                            {Qx.push(tx);Qy.push(ty);Qd.push(td);}
                     }
            }

    }

}

void doit()
{   char c;
    tot=0;
    for (int i=0;i<n;i++)
        scanf("%s",s[i]);
    for (int i=0;i<n;i++)
       for (int j=0;j<m;j++)
                 {c=s[i][j];
                  if (c=='S') {tr[0][0]=i; tr[0][1]=j;}
                  if (c=='E') {ex=i;ey=j;}
                  if (c=='K') {tot++;tr[tot][0]=i;tr[tot][1]=j;}
                 }
    tot++;
    tr[tot][0]=ex;
    tr[tot][1]=ey;
    ma=1<<(tot-1);

    for (int i=0;i<tot;i++)
        for (int j=0;j<4;j++)
            {bfs(tr[i][0],tr[i][1],j);
             for (int i1=0;i1<=tot;i1++)
                for (int j1=0;j1<4;j1++)
             d[i][j][i1][j1]=map[tr[i1][0]][tr[i1][1]][j1];
            }

    memset(dp,0x3f,sizeof(dp));
    for (int i=0;i<4;i++) dp[0][0][i]=1;


        for (int j=0;j<ma;j++)
          for (int i=0;i<tot;i++)
            for (int k=0;k<4;k++)
                 {int tmp=dp[i][j][k];
                  if (tmp==INF) continue;
                  for (int i1=1;i1<tot;i1++)
                     for (int k1=0;k1<4;k1++)
                        {   int j1=j|(1<<(i1-1));
                            dp[i1][j1][k1]=min(dp[i1][j1][k1],tmp+d[i][k][i1][k1]);
                        }

                 }
    int ans=INF;
    for (int i=0;i<tot;i++)
         for (int j=0;j<4;j++)
            for (int k=0;k<4;k++)
                ans=min(ans,dp[i][ma-1][j]+d[i][j][tot][k]);
    if (ans==INF) printf("%d\n",-1);else printf("%d\n",ans);


}
int main()
{
    while (scanf("%d%d",&n,&m)!=EOF) doit();
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值