Problem 0548 : Reindeer with no sense of direction  方向音痴のトナカイ

http://rose.u-aizu.ac.jp/onlinejudge/ProblemSet/description.jsp?id=0548&lang=jp

Problem 0548 : Reindeer with no sense of direction
方向音痴のトナカイ

  • 問題概要

ある一点から出発して、家を訪問していくのだが、

  • 家に配達したときしか方向転換できない。
  • 一度配達したところは通れない。

という、めんどくさい条件がある。

  • 解法

10*10のグリッドで家が23個あるので普通にしようとすると状態が多すぎる。
しかし、上の二つの条件から、

  • 実際に使用される条件は少ない。

なので、mapに突っ込んで、うしろからDPしてみました。
なぜ、後ろからか。

それは、前からだと、4方向+どこで降りて配達するかという選択肢があるが、
逆からだと、さいしょにぶつかった、配達済みのところをたどるしかないのでとてもスマートになる。

逆からDP、状態はプレゼントにIDをつけて、「どのプレゼントが配達済みなのか、いまどこにいるのか。」

という状態にしました。

  • ソース
#include<iostream>
#include<algorithm>
#include<map>
#include<queue>
using namespace std;


class State{
public:
  int x, y;
  bool p[24];
  State(){
    fill(p,p+24, false);
  }
  bool operator<(const State s)const{
    if(x != s.x ){
      return x < s.x;
    }
    if(y != s.y){
      return y < s.y;
    }
    for(int i=0; i<24; i++){
      if(p[i] != s.p[i]){
	return p[i] < s.p[i];
      }
    }
    return false;
  }
}; 


main(){

  int h, w;
  
  while(cin >> w >> h){
    if(w+h == 0){
      break;
    }
    int m[h][w];
    int cnt = 1, sx, sy;
    for(int i=0; i<h; i++){
      for(int j=0; j<w; j++){
	int tmp;
	cin >> tmp;
	if(tmp == 1){
	  m[i][j] = cnt;
	  cnt++;
	}
	else if(tmp == 2){
	  m[i][j] = 0;
	  sy = i;
	  sx = j;
	}
	else m[i][j] = -1;
      }
    }
    State s;
    s.x = sx;
    s.y = sy;
    map<State, int> nowmap;
    nowmap[s] = 1;
    int tx[] = {0, 0, -1, 1};
    int ty[] = {-1, 1, 0, 0};
    for(int i=0; i<cnt; i++){
      map<State, int> nextmap;
      for(map<State,int>::iterator it = nowmap.begin(); it != nowmap.end(); it++){
	for(int j=0; j<4; j++){
	  int nx = (*it).first.x, ny = (*it).first.y;
	  while(1){ 
	    nx += tx[j];
	    ny += ty[j];
	    if(nx < 0 || ny < 0 || nx >= w || ny >= h){
	      break;
	    }
	    if(m[ny][nx] == -1 || (i != cnt-1 && m[ny][nx] == 0)){
	      continue;
	    }
	    if((m[ny][nx] == 0 && i == cnt-1) || m[ny][nx] != 0){
	      State now = (*it).first;
	      int p = m[ny][nx];
	      if(now.p[p]){
		continue;
	      }
	      now.p[p] = true;
	      now.x = nx;
	      now.y = ny;
	      nextmap[now] += (*it).second;
	      break;
	    }
	  }
	}
      }
      nowmap = nextmap;
    }
    State end;
    end.x = sx;
    end.y = sy;
    for(int i=0; i<cnt; i++){
      end.p[i] = true;
    }
    cout << nowmap[end] << endl;
  }
}