#局部最小值
####**题目网址:**http://www.lydsy.com/JudgeOnline/problem.php?id=2669
##题目描述
有一个n行m列的整数矩阵,其中1到nm之间的每个整数恰好出现一次。如果一个格子比所有相邻格子(相邻是指有公共边或公共顶点)都小,我们说这个格子是局部极小值。
给出所有局部极小值的位置,你的任务是判断有多少个可能的矩阵。
##数据范围
1<=
n
n
n<=4, 1<=
m
m
m<=7
##题解
这一题,挺难的,经过了我几个小时的努力,我还是对了,O(∩_∩)O~~
动态规划,F[
i
i
i][
s
s
s]表示前
i
i
i个数已经填完了,位置为
X
X
X的点的填充情况为
s
s
s时(
s
s
s为2进制),填数的方案有多少。预处理出
R
e
s
t
Rest
Rest数组,
R
e
s
t
s
Rest_s
Rests(
s
s
s为2进制)表示位置为
X
X
X的点的填充情况为
s
s
s时,有多少个位置可以放数(包括位置为
X
X
X的点)。
状态转移方程显然为:
[外链图片转存中…(img-ly0djsXn-1650997478448)]
其中-
i
i
i+1等于-(
i
i
i-1)。
但是我们发现这样做会把不是局部最小值的位置也会当成局部最小值,于是我们算出所有把别的位置也当成 X X X的情况(不重复),对于每种情况跑一边动态规划。如果多选偶数个 X X X,则加到答案贡献上,如果是奇数个,则对答案的贡献为负数。
##Code(Pascal)
label 123;
CONST
mo=12345678;
var
wz:array[1..8,1..2] of longint=
((-1,-1),(-1,0),(-1,1),(0,-1),(0,1),(1,-1),(1,0),(1,1));
n,m,j,k,l,t,y,i,o,p,kww:longint;
ch:array[0..5,0..8] of char;
jk,rr:array[0..5,0..8] of longint;
kx:array[0..30,1..2] of longint;
bz:array[0..30] of boolean;
m2:array[0..10] of longint;
f:array[0..28,0..512] of int64;
rest:array[0..512] of int64;
lz:array[0..30] of longint;
ans:int64;
function ok(a,b:longint):boolean;
begin
if (a>0) and (a<=n) and (b>0) and (b<=m) then exit(true)
else exit(false);
end;
function js:int64;
var
i,j,l,s,p:longint;
begin
for i:=0 to m2[k]*2-1 do
begin
rest[i]:=0;
inc(kww);
for j:=1 to k do
if m2[j] and i=0 then
begin
rr[kx[j,1],kx[j,2]]:=kww;
for l:=1 to 8 do
rr[kx[j,1]+wz[l,1],kx[j,2]+wz[l,2]]:=kww;
end;
for j:=1 to n do
for l:=1 to m do
if rr[j,l]<>kww then inc(rest[i]);
end;
if k=0 then
begin
js:=1;
for l:=1 to n*m do
js:=(js*l) mod mo;
exit;
end;
for i:=1 to n*m do
for s:=0 to m2[k]*2-1 do
f[i,s]:=0;
f[0,0]:=1;
for i:=1 to n*m do
for s:=0 to m2[k]*2-1 do
if rest[s]-i+1>0 then
begin
f[i,s]:=f[i-1,s]*(rest[s]-i+1) mod mo;
for l:=1 to k do
if s and m2[l]>0 then
f[i,s]:=(f[i,s]+f[i-1,s-m2[l]]) mod mo;
end;
js:=f[n*m,m2[k]*2-1];
end;
procedure dg(o,kk,uu:longint);
var
i,j,l,pp,ss:longint;
begin
ans:=(ans+o*js+mo) mod mo;
ss:=kk*m+uu;
for i:=kk to n do
for l:=1 to m do
if i*m+l>=ss then
if ch[i,l]='.' then
begin
pp:=0;
for j:=1 to 8 do
if ch[i+wz[j,1],l+wz[j,2]]='X' then
begin
inc(pp);
break;
end;
if pp=0 then
begin
inc(k);
kx[k,1]:=i;
kx[k,2]:=l;
ch[i,l]:='X';
dg(0-o,i,l+1);
dec(k);
ch[i,l]:='.';
end;
end;
end;
begin
m2[1]:=1;
for i:=2 to 10 do
m2[i]:=m2[i-1]*2;
k:=0;
readln(n,m);
for i:=1 to n do
begin
for l:=1 to m do
begin
read(ch[i,l]);
if ch[i,l]='X' then
begin
inc(k);
kx[k,1]:=i;
kx[k,2]:=l;
end;
end;
readln;
end;
for i:=1 to n do
for l:=1 to m do
if ch[i,l]='X' then
for j:=1 to 8 do
if (ch[i+wz[j,1],l+wz[j,2]]='X') and ok(i+wz[j,1],l+wz[j,2]) then
begin
ans:=0;
goto 123;
end;
ans:=0;
if k<>0 then
dg(1,1,1);
123:writeln(ans);
end.