《随机题库练习10》D

HDU4166的一个进阶版吧.
思路:
首先联想到bfs的性质.
当我们搜素到(x,y)点时,那么这时的距离一定是到这个点最短的距离.
对于到X点的最短距离,可能会存在多个点到它的距离满足到x的最短距离.
但是这样的情况只是说明最短的路径很多,但是到x点的最短距离肯定是不变的.
因为从x->y的最短路径肯定是优于(其他到x的>最短路径的距离)->y的距离.
所以说我们只需要统计到这个点的路径和到这个点的最短路径相同的点,那么就说明可以构成一条最短路径.
然后联系起bfs的性质,当我们第一次搜素到这个点时,最短距离肯定就是这个距离.
然后最后进行一下判断,注意的是方向不同也算不同的状态.
然后方案数采用dp转移.
这里可以任意走X步,那么直接从1开始枚举步数.如果碰到炸弹或者出界,那么就说明不能再往前了,就退出该次循环.

#include
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const int N = 105;
const int Mod = 1e6;
#define pi acos(-1)
#define INF 1e8
#define INM INT_MIN
#define pb(a)  push_back(a)
#define mk(a,b) make_pair(a,b)
#define dbg(x) cout << "now this num is " << x << endl;
#define met0(axx) memset(axx,0,sizeof(axx));
#define metf(axx) memset(axx,-1,sizeof(axx));
#define sd(ax) scanf("%d",&ax)
#define sld(ax) scanf("%lld",&ax)
#define sldd(ax,bx) scanf("%lld %lld",&ax,&bx)
#define sdd(ax,bx) scanf("%d %d",&ax,&bx)
#define sddd(ax,bx,cx) scanf("%d %d %d",&ax,&bx,&cx)
#define sfd(ax) scanf("%lf",&ax)
#define sfdd(ax,bx) scanf("%lf %lf",&ax,&bx)
#define pr(a) printf("%d\n",a)
#define plr(a) printf("%lld\n",a)
int ex,ey,sx,sy,sz,Minn = -1,ans,n,m;
string mp[1005];
int b[4][2] = {-1,0,1,0,0,1,0,-1},dis[1005][1005][4];
LL cnt[1005][1005][4];//到i,j位置时且朝向为z时的方案数.
map<char,int> mp1;
struct Node{int x,y,z;};
void init(){mp1['N'] = 0,mp1['S'] = 1,mp1['E'] = 2,mp1['W']  = 3;}
int check1(int z)//左转
{
 if(z == 0) return 3;
 if(z == 1) return 2;
 if(z == 2) return 0;
 if(z == 3) return 1;
}
int check2(int z)//右转
{
 if(z == 0) return 2;
 if(z == 1) return 3;
 if(z == 2) return 1;
 if(z == 3) return 0;
}
void bfs(int x,int y,int z)
{
 Node p;
 queue<Node> Q;
 p.x = x,p.y = y,p.z = z;
 dis[x][y][z] = 0;cnt[x][y][z] = 1;
 Q.push(p);
 while(!Q.empty())
 {
  Node q = Q.front();Q.pop();
  int px = q.x,py = q.y,pz = check1(q.z);//左转
  if(dis[px][py][pz] == -1)//第一次走到这种状态时,更新这种状态的最短路径
  {
   dis[px][py][pz] = dis[q.x][q.y][q.z]+1;
   cnt[px][py][pz] = (cnt[px][py][pz]+cnt[q.x][q.y][q.z])%Mod;
   p.x = px,p.y = py,p.z = pz;
   Q.push(p);
  }
  else if(dis[q.x][q.y][q.z]+1 == dis[px][py][pz]) cnt[px][py][pz] = (cnt[px][py][pz]+cnt[q.x][q.y][q.z])%Mod;
  px = q.x,py = q.y,pz = check2(q.z);//右转
  if(dis[px][py][pz] == -1)
  {
   dis[px][py][pz] = dis[q.x][q.y][q.z]+1;
   cnt[px][py][pz] = (cnt[px][py][pz]+cnt[q.x][q.y][q.z])%Mod;
   p.x = px,p.y = py,p.z = pz;
   Q.push(p);
  }
  else if(dis[q.x][q.y][q.z]+1 == dis[px][py][pz]) cnt[px][py][pz] = (cnt[px][py][pz]+cnt[q.x][q.y][q.z])%Mod;
  for(int k=1;;k++)
  {
   px = q.x+k*b[q.z][0],py = q.y+k*b[q.z][1],pz = q.z;
   if(px >= 0 && px < n && py >= 0 && py < m && mp[px][py] != '*')
   {
    if(dis[px][py][pz] == -1)
    {
     dis[px][py][pz] = dis[q.x][q.y][q.z]+1;
     cnt[px][py][pz] = (cnt[px][py][pz]+cnt[q.x][q.y][q.z])%Mod;
     p.x = px,p.y = py,p.z = pz;
     Q.push(p);
    }
    else if(dis[q.x][q.y][q.z]+1 == dis[px][py][pz]) cnt[px][py][pz] = (cnt[px][py][pz]+cnt[q.x][q.y][q.z])%Mod;
   }
   else break;//当遇到不能走时,或者走到边界时退出.
  }
 }
 for(int i=0;i<4;++i) if(dis[ex][ey][i] != -1) ans = min(ans,dis[ex][ey][i]);
 if(ans == INF) printf("0 0\n");
 else
 {
  LL temp = 0;
  for(int i=0;i<4;++i) if(dis[ex][ey][i] == ans) temp = (temp+cnt[ex][ey][i])%Mod;
  printf("%d %lld\n",ans,temp);
 }
}
int main()
{
 init();
 while(~sdd(n,m),n||m)
 {
  metf(dis);met0(cnt);ans = INF;
  for(int i=0;i<n;++i) cin >> mp[i];
  for(int i=0;i<n;++i)
  {
   for(int j=0;j<m;++j)
   {
    if(mp[i][j] != '*' && mp[i][j] != 'X' && mp[i][j] != '.') sx = i,sy = j,sz = mp1[mp[i][j]];
    if(mp[i][j] == 'X') ex = i,ey = j;
   }
  }
  bfs(sx,sy,sz);
 }
 system("pause");
 return 0;
}

你可能感兴趣的:(《随机题库练习10》D)