poj 1739 Tony's Tour 插头dp

本文详细解析POJ1739问题的解题思路,着重解释了理解并修正插头修改逻辑的关键步骤。通过实例分析,解决了数据量大时结果偏少的问题,并提供了正确的代码实现。最终附上了代码,帮助读者掌握该问题的解决方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:http://poj.org/problem?id=1739

POJ 1739

题目大意:给一个最大8*8的会有一些地方不能走的图,指定左下角(N,1)为起点,右下角(N,M)为终点,求哈密尔顿链路的个数。



首先,我们要先看cdq的论文。

在看过以后,我有一个疑惑,就是关于修改括号的。

虽然很多人都会,但是我就是没看懂,Oct_gap说论文里有,但是我没领悟到。

cdq论文的case2里有一个,就是当左边和上面插头一样且不为0时,要修改插头。

我在此wa了无限次,不管有没有人和我一样,我都要写出来!

如何修改插头,首先,如果两个插头都是左插头,那么就往右边搜索,找到第一个没有匹配的右插头,改成左插头。

如果两个都是右插头,那么就往左边找,第一个没匹配的左插头,改为右插头。

具体实现:(都为左插头)

s:=1;

for i:=j+2(就是这俩插头个后面那个格子) to m+1 do

  begin

     if c[i]=1 then s:=s+1;

     if c[i]=2 then s:=s-1;

     if s=0 then begin  c[i]:=1 break; end;

  end;

这个问题如果理解错了,主要表现为:数据大时,结果会比答案少一点点!

排除了这个问题,我们可以起点和终点视为联通的,答案是左下角是左插头,右下角是右插头,其余为0的情况!

其他和cdq论文是一样的(其实这全部都一样,只是那个问题我没懂)

最后附上代码:(的notepad++里打的,那里面缩进都是正常的,在这缩进什么的就无视好了)

type
  arr=array[0..12] of longint;
var
  fuck,sum,n,m,i,j,k,l,t:longint;
  c,h:arr;
  f:array[0..10,0..10,0..20000] of longint;
  s:string;
  g:array[0..10,0..10] of longint;
procedure unzip(k:longint;var c:arr);  {把k解压成数组c}
  var i:longint;
  begin
    for i:=m+1 downto 1 do begin c[i]:=k mod 3;k:=k div 3; end;
  end;
procedure zip(c:arr;i,j,k:longint);  {把c压缩成k 并且更新}
  var
    t,l:longint;
  begin
    t:=0;for l:=1 to m+1 do t:=t*3+c[l];
f[i,j,t]:=f[i,j,t]+k;
  end;
begin
  readln(n,m);
  while (n<>0) and (m<>0) do begin 
  fillchar(f,sizeof(f),0);fillchar(g,sizeof(g),0);
  for i:=1 to n do begin
readln(s);
for j:=1 to m do
 if s[j]='.' then g[i,j]:=1;
  end;  
  h[1]:=1;
  for i:=2 to 11 do 
    h[i]:=h[i-1]*3;
  f[0,m,0]:=1;
  for i:=1 to n do begin
for j:=0 to h[m+1]-1 do
 f[i,0,j]:=f[i-1,m,j*3];
for j:=0 to m-1 do
 for k:=0 to h[m+2]-1 do
   if f[i,j,k]>0 then 
 begin
   unzip(k,c);
   if g[i,j+1]=1 then 
 begin
           if (c[j+1]=c[j+2]) and (c[j+1]=0) then {左 上 没有}
     begin
           c[j+1]:=1;c[j+2]:=2;
zip(c,i,j+1,f[i,j,k]);
       continue;
         end;
       if (c[j+1]=0) and (c[j+2]>0) then {上面有 左边没有}
 begin
           f[i,j+1,k]:=f[i,j+1,k]+f[i,j,k];
           c[j+1]:=c[j+2];c[j+2]:=0;
zip(c,i,j+1,f[i,j,k]);
       continue;
         end;
           if (c[j+1]>0) and (c[j+2]=0) then {上面没有 左边有}
     begin
           f[i,j+1,k]:=f[i,j+1,k]+f[i,j,k];
           c[j+2]:=c[j+1];c[j+1]:=0;
zip(c,i,j+1,f[i,j,k]);
       continue;
         end;
if (c[j+1]=2) and (c[j+2]=1) then {左边是右插头 上面是左插头}
 begin
c[j+1]:=0;c[j+2]:=0;
zip(c,i,j+1,f[i,j,k]);
continue;
end;
       if (c[j+1]=c[j+2]) then {两边插头一样 不为0}
     begin
           if c[j+1]=1 then 
     begin
   fuck:=1;
           for l:=j+3 to m+1 do 
             begin
   if c[l]=2 then fuck:=fuck-1;
if c[l]=1 then fuck:=fuck+1;
if fuck=0 then 
             begin 
               c[l]:=1;
       break;
             end;
     end;
         end
   else
 begin
   fuck:=1;
           for l:=j downto 1 do 
             begin
   if c[l]=1 then fuck:=fuck-1;
if c[l]=2 then fuck:=fuck+1;
               if fuck=0 then 
 begin 
       c[l]:=2;
               break; 
         end;
 end;
 end;
       c[j+1]:=0;c[j+2]:=0;
   zip(c,i,j+1,f[i,j,k]);
     end;
     end
   else 
 if (c[j+1]=0) and (c[j+2]=0) then f[i,j+1,k]:=f[i,j,k]+f[i,j+1,k];{图中点为#时}
     end;
  end;
  fillchar(c,sizeof(c),0);t:=0;c[1]:=1;c[m]:=2;
  for i:=1 to m+1 do
    t:=t*3+c[i];
  writeln(f[n,m,t]);
  readln(n,m);
  end;
end.



下面是我错的数据:

6 6

#.....

......

......

..#...

......

......

86

错误答案:83


6 6

..#...

....#.

.#..#.

......

......

......

17

错误答案:15


6 6

......

.#....

.#....

......

......

......

120

错误答案:112


最后,感谢Oct_gap神犇帮我找出错误,我一定要争取国一!!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值