您的位置:首页 > 其它

POJ 1739 Tony's Tour (插头DP,轮廓线DP)

2015-09-06 17:37 447 查看
题意:给一个n*m的矩阵,其中#是障碍格子,其他则是必走的格子,问从左下角的格子走到右下角的格子有多少种方式。

思路:

  注意有可能答案是0,就是障碍格子阻挡住了去路。

  插头DP有两种比较常见的表示连通信息的方式:

  (1)最小表示法

  (2)括号表示法

  本文用括号表示法实现。左括号为1,右括号为2,用两个位来表示。轮廓线上最多需要表示9个插头信息,那么就是18个位即可。插头的状态转移有如下几种:

  (1)右插头和下插头都是同个方向的括号,则合并他们,再将对应的两外两个半括号给改成一对。比如 ((())) 合并完变成##()(),橙色的就是需要改的地方。

  (2)右插头是')',下插头是'(',则合并他们,且无需任何修改。

  (3)右插头是'(',下插头是')',则不能合并,因为一旦合并,肯定是组成1个圆了,就会有多个连通分量的产生。自己画画就知道了。

  (4)右插头是'(',下插头是')',只有在最后一个非障碍格子(按行从左到右遍历的)的时候才可以合并,

  (5)右/下插头只有1个插头存在,那么可以延续它,可以分别往下和右两个方向。

  (6)没有插头,那么只能另开一对新括号了,分别对应右和下插头的位置。

  (7)障碍格子,只有该位置的两个插头都是空的时候才可以转移,且轮廓线无需修改。

  因为状态本来就不多,用哈希表来存状态会比较快且比较省时间,哈希表实现是摘别人的。每次只需要用上一个格子中的状态来转移到当前格子的状态。本题是不能有连通分量产生的,所以只需要在初始的状态设置起点和终点是一对括号,那就相当于在找哈密顿回路了,和Formula 1就一样了。

struct Hash_Map
{
static const int mod=12357;
static const int N=50000;
int head[mod];      //桶指针
int next
;        //记录链的信息
int status
;      //状态
LL  value
;       //状态对应的DP值。
int size;
void clear()    //清除哈希表中的状态
{
memset(head, -1, sizeof(head));
size = 0;
}

void insert(int st, LL val)  //插入状态st的值为val
{
int h = st%mod;
for(int i=head[h]; i!=-1; i=next[i])
{
if(status[i] == st) //这个状态已经存在,累加进去。
{
value[i] += val;
return ;
}
}
status[size]= st;           //找不到状态st,则插入st。
value[size] = val;
next[size] = head[h] ;      //新插入的元素在队头
head[h] = size++;
}
}hashmap[2];


Hash_Map
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: