题目: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神犇帮我找出错误,我一定要争取国一!!