POJ 3414 Pots

問題

容量AリットルとBリットルの二つの容器がある。
以下の操作を繰り返してどちらかの容器に入っている水の量をCリットルする。
最短手順の操作をどれか一つ出力せよ。
不可能な場合impossibleを出力せよ。

  • Aの容器を満タンにする
  • Bの容器を満タンにする
  • Aの容器に入っている水を全て捨てる
  • Aの容器に入っている水を全て捨てる
  • Aの容器からBの容器に水を移す。移し終わった後、Aが空になっているか、Bが満タンになっていなければならない。
  • Bの容器からAの容器に水を移す。移し終わった後、Bが空になっているか、Aが満タンになっていなければならない。

制約条件

A,B≦100
C≦max(A,B)

方針

幅優先探索+経路復元。

ソースコード

int A,B,C;
int prev[101][101],op[101][101];
int ans[11000], sz;

int main(){
  memset(prev,-1,sizeof(prev));
  scanf("%d%d%d",&A,&B,&C);
  queue<int> q;
  q.push(0);
  while(!q.empty()){
    int a=q.front()/101, b=q.front()%101; q.pop();
    if(a==C||b==C){
      for(;a||b;){
        ans[sz++]=op[a][b];
        int na=prev[a][b]/101, nb=prev[a][b]%101;
        a=na; b=nb;
      }
      reverse(ans,ans+sz);
      printf("%d\n",sz);
      rep(i,sz)switch(ans[i]){
        case 1: puts("FILL(1)"); break;
        case 2: puts("FILL(2)"); break;
        case 3: puts("DROP(1)"); break;
        case 4: puts("DROP(2)"); break;
        case 5: puts("POUR(2,1)"); break;
        case 6: puts("POUR(1,2)");
      }
      return 0;
    }
    
    if(prev[0][b]<0)
      prev[0][b]=a*101+b, op[0][b]=3, q.push(b);
    if(prev[a][0]<0)
      prev[a][0]=a*101+b, op[a][0]=4, q.push(a*101);
    if(prev[A][b]<0)
      prev[A][b]=a*101+b, op[A][b]=1, q.push(A*101+b);
    if(prev[a][B]<0)
      prev[a][B]=a*101+b, op[a][B]=2, q.push(a*101+B);
    
    int na=a+b, nb=0;
    if(na>A)nb=na-A, na=A;
    if(prev[na][nb]<0)
      prev[na][nb]=a*101+b, op[na][nb]=5, q.push(na*101+nb);
    na=0, nb=a+b;
    if(nb>B)na=nb-B, nb=B;
    if(prev[na][nb]<0)
      prev[na][nb]=a*101+b, op[na][nb]=6, q.push(na*101+nb);
  }
  puts("impossible");
  
  return 0;
}