PKU : 3414 - Pots

問題概要

http://poj.org/problem?id=3414
容量A,Bまで入る2つのポットがあります.
最初の水の量は, 最初2つとも0です.
このとき, 次の操作を行いながら, どちらかのポットの容量をCにしてください.

  • FILL(i) : iのポットを満タンにする
  • DROP(i) : iのポットを空にする
  • FILL(i,j) : iのポットからjのポットに水をうつす
    • iが空になるか, jが満タンになるまで, これを行う

アルゴリズム

BFSでできます.
状態は, 高々100*100なので, オーダは心配しなくて大丈夫です.

反省点

操作の情報はStateクラスの中にもたせるのではなく, 操作復元用の配列を作って行うべきだった.
しめじたんのブログがいい例.

プログラム

typedef pair<int,int> P;

#define REP(i,n,m) for(int i=n;i<m;i++)
#define rep(i,n) REP(i,0,n)

class State{
public:
  int a,b;
  vector<P> v;

  State(){}
  State(int _a,int _b,vector<P> _v){
    a = _a;
    b = _b;
    v = _v;
  }
};

int a,b,c;

void solve(){
  queue<State> open;
  bool closed[102][102];
  open.push(State(0,0,vector<P>()));
  memset(closed,0,sizeof(closed));

  vector<P> ans;

  while(!open.empty()){
    State st = open.front(); open.pop();
    if(closed[st.a][st.b]) continue;
    closed[st.a][st.b] = true;

    if(st.a == c || st.b == c){
      ans = st.v;
      break;
    }

    //FILL(1)
    int idx = st.v.size();
    st.v.push_back(P(0,1));
    open.push(State(a,st.b,st.v));

    //FILL(2)
    st.v[idx] = P(0,2);
    open.push(State(st.a,b,st.v));

    //DROP(1)
    st.v[idx] = P(0,-1);
    open.push(State(0,st.b,st.v));

    //DROP(2)
    st.v[idx] = P(0,-2);
    open.push(State(st.a,0,st.v));

    int A = st.a;
    int B = st.b;

    //POUR(1,2)
    st.v[idx] = P(1,2);
    open.push(State(max(0,A-(b-B)), min(b,B+A),st.v));

    //POUR(2,1)
    st.v[idx] = P(2,1);
    open.push(State(min(a,A+B), max(0,B-(a-A)),st.v));
  }

  if(ans.empty()){
    cout<<"impossible\n";
  }
  else{
    cout<<ans.size()<<endl;
    rep(i,ans.size()){
      if(ans[i].first > 0){
        printf("POUR(%d,%d)\n",ans[i].first,ans[i].second);
      }
      else if(ans[i].second > 0){
        printf("FILL(%d)\n",ans[i].second);
      }
      else{
        printf("DROP(%d)\n",-ans[i].second);
      }
    }
  }
}

int main(){
  cin>>a>>b>>c;
  solve();
}