読者です 読者をやめる 読者になる 読者になる

土下座しながら探索中

主に競技プログラミング

HDU 1693 : Eat The Trees

HDU 插头DP プラグDP

問題リンク : Problem - 1693

問題概要:
h*w のグリッドがあり、各マスには木が生えているかなにもないかのどちらかである
化け物が木の生えているマスに現れ、隣接するマスで木が生えているマスに移動しどんどん木を食べて、その後に消える
移動経路が円になるように移動する ( 現れるマスと消えるマスは同じ )
一度移動した後はそのマスの木はなくなるため、2度訪れることはできない
まだ木が残っている場合は再度現れて木を食べる
木の食べ方の移動経路は何通り存在するか?

解法 :
插头DP
日本でいう一行覚えるDPなのだろうか、
プラグを繋いだか繋がないかで1か0を割り当てDP

コード:

#include<iostream>
#include<cstdio>

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

using namespace std;

typedef long long ll;

int h,w;
int field[20][20];
ll dp[400][1<<15];

void compute(){
  rep(i,h*w+1) rep(j,(1<<(w+1))) dp[i][j] = 0LL;
  dp[0][0] = 1LL;
  
  rep(y,h) rep(x,w) {
    int cur = x + y * w, next = cur + 1;

    rep(bitmask,(1<<(w+1)))if( dp[cur][bitmask] ){

      int left = bitmask & (1<<x);
      int top  = bitmask & (1<<(x+1));

      if( field[y][x] ) {
	if( left && top ) {
	  int rleft = ~(1<<x);
	  int rtop  = ~(1<<(x+1));
	  int nbitmask = ( bitmask & rleft & rtop );
	  if( x == w-1 ) { nbitmask <<= 1; }
	  if( nbitmask <= (1<<(w+1))-1 ) {
	    dp[next][nbitmask] += dp[cur][bitmask];
	  }
	} else if( !left && !top ) {
	  int nbitmask = bitmask | (1<<x) | (1<<(x+1));
	  if( x == w-1 ) { nbitmask <<= 1; }
	  if( nbitmask <= (1<<(w+1))-1 ) {
	    dp[next][nbitmask] += dp[cur][bitmask];
	  }
	} else {
	  int rleft = ~(1<<x);
	  int rtop  = ~(1<<(x+1));
	  int nbitmask = ( bitmask & rleft & rtop );

	  nbitmask |= (1<<x);
	  if( x == w-1 ) { nbitmask <<= 1; }
	  if( nbitmask <= (1<<(w+1))-1 ) {
	    dp[next][nbitmask] += dp[cur][bitmask];
	  }

	  nbitmask = ( bitmask & rleft & rtop );
	  nbitmask |= (1<<(x+1));
	  if( x == w-1 ) { nbitmask <<= 1; }
	  if( nbitmask <= (1<<(w+1))-1 ) {
	    dp[next][nbitmask] += dp[cur][bitmask];
	  }

	}
      } else {
	if( !left && !top ) {
	  int nbitmask = bitmask;
	  if( x == w-1 ) { nbitmask <<= 1;  } 
	  if( nbitmask <= (1<<(w+1))-1 ) {
	    dp[next][nbitmask] += dp[cur][bitmask];
	  }
	}
      }
    }
  }

  cout << dp[h*w][0];
}

int main(){
  int T,CNT = 1;
  cin >> T;
  while( T-- ) {
    cin >> h >> w;
    rep(i,h) rep(j,w) cin >> field[i][j];
    printf("Case %d: There are ",CNT++);
    compute();
    puts(" ways to eat the trees.");
  }
  return 0;
}