局部最小值
题目网址:http://www.lydsy.com/JudgeOnline/problem.php?id=2669
题目描述
有一个n行m列的整数矩阵,其中1到nm之间的每个整数恰好出现一次。如果一个格子比所有相邻格子(相邻是指有公共边或公共顶点)都小,我们说这个格子是局部极小值。 给出所有局部极小值的位置,你的任务是判断有多少个可能的矩阵。
数据范围
1<=
n
<=4, 1<=m<=7
题解
这一题,挺难的,经过了我几个小时的努力,我还是对了,O(∩_∩)O~~ 动态规划,F[
i
][s]表示前
i
个数已经填完了,位置为X的点的填充情况为
s
时(s为2进制),填数的方案有多少。预处理出
Rest
数组,
Rests
(
s
为2进制)表示位置为X的点的填充情况为
s
时,有多少个位置可以放数(包括位置为X的点)。 状态转移方程显然为: 其中-
i
+1等于-(i-1)。
但是我们发现这样做会把不是局部最小值的位置也会当成局部最小值,于是我们算出所有把别的位置也当成
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.
转载请注明原文地址: https://ju.6miu.com/read-1308901.html