BZOJ 1948 CEOI 2006 Connect 状态压缩动态规划

10 篇文章 0 订阅

BZOJ题面好像不全。
什么POI,CEOI吧。。还是去看原题比较好,比如
http://www.hsin.hr/ceoi2006/index.php?page=tasks
http://www.hsin.hr/ceoi2006/tasks/day2/connect.pdf
http://www.hsin.hr/ceoi2006/tasks/day2/connect_test.zip
http://www.hsin.hr/ceoi2006/tasks/solutions.pdf
http://www.hsin.hr/ceoi2006/tasks/solutions.zip

考虑每个方格的状态,发现有11种状态,分别是
空(1)、路径穿过(6)、X所在格(4)。

#include <cstdio>
#include <cstring>
#define rep(i,j,k) for(i=j;i<k;++i)
using namespace std;
const int N = 16, M = 64;
int n, m;
char a[2 * N][2 * M];
int how[N][M];
short dp[N][M][1 << 12][2];
const short inf = 10000;

char b[3][11][4] = {
   { "# #", "# #", "#.#", "# #", "# #", "# #", "#.#", "#.#", "#.#", "# #", "# #" },
   { "   ", ".X ", " X ", " X.", " X ", "...", " . ", ".. ", " ..", " ..", ".. " },
   { "# #", "# #", "# #", "# #", "#.#", "# #", "#.#", "# #", "# #", "#.#", "#.#" },
};

int set_bit(int s, int i, int v) { return (s & ~(1 << i)) | (v << i); }

short rec( int r, int c, int mask, int U, int reconstruct ) {
   if( r == n ) return rec( 0, c+1, mask, 0, reconstruct );
   if( c == m ) return 0;

   short &ret = dp[r][c][mask][U];
   if( !reconstruct && ret >= 0 ) return ret;

   ret = inf;

   int L = (mask>>r)&1;
   int R = a[2*r+1][2*c+2] == ' ';
   int D = a[2*r+2][2*c+1] == ' ';
   int X = a[2*r+1][2*c+1] == 'X';

   int type=0, h1 = 0, state = 0, u = 0;

   #define tst(tp, t1, mk, uu) { \
      int v = t1 + rec(r + 1, c, mk, uu, 0 ); \
      if( v < ret ) { ret = v; type = tp; h1=t1; state = mk; u = uu; } \
   }

   if (!X && !L && !U && 1 && 1) tst( 0, 0, set_bit(mask, r, 0), 0); // empty

   if ( X &&  L && !U && 1 && 1) tst( 1, 1, set_bit(mask, r, 0), 0); // left
   if ( X && !L &&  U && 1 && 1) tst( 2, 1, set_bit(mask, r, 0), 0); // up
   if ( X && !L && !U && R && 1) tst( 3, 1, set_bit(mask, r, 1), 0); // right
   if ( X && !L && !U && 1 && D) tst( 4, 1, set_bit(mask, r, 0), 1); // down

   if (!X &&  L && !U && R && 1) tst( 5, 2, set_bit(mask, r, 1), 0 ); // left-right
   if (!X && !L &&  U && 1 && D) tst( 6, 2, set_bit(mask, r, 0), 1 ); // up-down

   if (!X &&  L &&  U && 1 && 1) tst( 7, 2, set_bit(mask, r, 0), 0); // left-up
   if (!X && !L &&  U && R && 1) tst( 8, 2, set_bit(mask, r, 1), 0); // up-right
   if (!X && !L && !U && R && D) tst( 9, 2, set_bit(mask, r, 1), 1); // right-down
   if (!X &&  L && !U && 1 && D) tst(10, 2, set_bit(mask, r, 0), 1); // down-left

   if (reconstruct) {
      how[r][c] = type;
      rec(r + 1, c, state, u, 1 );
   }

   return ret;
}

int main( void ) {
   int i, j, k, l;
   scanf( "%d%d ", &n, &m );
   rep(i,0,n) fgets(a[i], 2 * M, stdin);
   n /= 2; m /= 2;

   memset(dp, -1, sizeof dp);
   printf("%d\n", rec(0, 0, 0, 0, 1));

   rep(i,0,n) rep(j,0,m) rep(k,0,3) rep(l,0,3)
      if (b[k][how[i][j]][l] != ' ')
         a[2 * i + k][2 * j + l] = b[k][how[i][j]][l];
   rep(i,0,2*n+1) puts(a[i]);
   return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值