[POJ 3133]

Manhattan Wiring

插头DP

题意:给出一个最多9*9的格盘描述,其中有两个2和两个3,求将两个2和3分别用不相交的线段相连所需的最短线长。线不能交叉且仅能经过空格。

明确是插头DP后,首先要考虑如何表示状态。这题特殊之处在于线段有两条,且需要和指定的端点相连。那么,最关键的是确定如何表达有效的终状态。

考虑以下解方案:用0表示空插头,2和3分别有相应插头。那么这里每个位置需要2bit,总共是2*10=20bit。再用最低的4个bit分别表示4个端点是否有连接,由此便能用一个int来表示轮廓线状态u。判断终状态时,直接用u==15即可。其正确性在于,题目所求的是最短线长,那么若4个端点已连,且当前没有空线头,则端点间必定已存在连线。同时也可能存在不与任何端点相连的线环,但线环仅仅是增加了总线长,不影响正确性。

实现方面,由于状态数为1<<24,若直接存下各个状态的最短线长,只能用char数组,由于题目数据范围不大,这是可行的。但一开始还是用了int数组和hash处理(u%10007)。按理说直接访问状态应该要比hash快,但事实上后者比前者要快两倍多(500ms VS 1600MS)。猜测是由于hash过后状态值较为接近,内存访问要更为集中。 虽然再加一些状态剪枝应该可以更快……但当前的代码长度竟已超过了5K,实在是不太明白那些2K左右跑出300ms的代码是怎么写的…… =(