[CodeVs1050]棋盘染色2(状态压缩DP)

时间:2023-03-09 22:52:48
[CodeVs1050]棋盘染色2(状态压缩DP)

题目大意:有一个5*N(≤100)的棋盘,棋盘中的一些格子已经被染成了黑色,求最少对多少格子染色,所有的黑色能连成一块。

这题卡了我1h,写了2.6k的代码,清明作业一坨还没做啊。。。之前一直以为这题是插头DP,结果今天一看发现不用>_<,虽然还是状压DP。

因为只有5列,所以每行至多有3个黑色联通块,即黑,白,黑,白,黑,其他的情况都少于3个联通块了,所以我们可以把联通块标号。0表示白色,1表示1号联通块,2和3同理,所以我们可以用4进制来表示每一行的状态。则下一行的黑色若与上一行的黑色连接,它的联通块编号即上一行与其连接的黑色的联通块编号。对于每一个状态,枚举下一层要涂黑哪个白色,然后转移,最后一层所有黑色为同一联通块就更新答案。这样这道题就做完了,思路很简单,但是写起来确实有点麻烦。。。不过写那么久一定是我太弱了= =。。。

代码如下:

type
node=array[..]of longint;
var
f:array[..,..]of longint;
a:array[..]of longint;
h:array[..,..]of longint;
s,t:node;
ch:char;
n,i,j,ans:longint; function lowbit(x:longint):longint;
begin
if x= then exit();
exit(lowbit(x-(x and -x))+);
end; procedure change(var a:node;sum1,sum2:longint);
var
i:longint;
begin
for i:= to do
if a[i]=sum1 then
begin
a[i]:=sum2;
if (a[i-]<>)and(a[i-]<) then change(a,a[i-],sum2);
if (a[i+]<>)and(a[i+]<) then change(a,a[i+],sum2);
end;
end; procedure work(var a:node);
var
i,sum:longint;
begin
sum:=;
for i:= to do
if (a[i]<>)and(a[i]<) then
begin
inc(sum);
change(a,a[i],sum);
end;
for i:= to do
if a[i]> then dec(a[i],);
end; procedure bfs;
var
i,j,k,yy,front,rear:longint;
flag:boolean;
begin
h[][]:=;h[][]:=;
front:=;rear:=;
while front<rear do
begin
inc(front);
yy:=h[front][];
for i:= to do
begin
s[i]:=h[front][] and ;
h[front][]:=h[front][]>>;
end;
h[front][]:=yy;
if h[front][]=n then
begin
flag:=true;
for i:= to do
if s[i]> then flag:=false;
if flag then
if ans>f[h[front][],h[front][]] then ans:=f[h[front][]][h[front][]];
continue;
end;
for i:= to (<<)- do
if i and a[h[front][]+]= then
begin
for j:= to do
t[j]:=(((a[h[front][]+]+i)>>(j-))and )*(j+);
k:=;
for j:= to do
if (s[j]>) and (t[j]>) then
begin
t[j]:=s[j];
k:=k or (<<s[j]);
end;
flag:=true;
for j:= to do
if (s[j]>)and(k and (<<s[j])=) then flag:=false;
if flag=false then continue;
work(t);
k:=;
for j:= downto do
k:=k<<+t[j];
if f[h[front][]+,k]> then
begin
inc(rear);
h[rear][]:=h[front][]+;
h[rear][]:=k;
end;
if f[h[front][]+][k]>f[h[front][]][h[front][]]+lowbit(i) then
f[h[front][]+][k]:=f[h[front][]][h[front][]]+lowbit(i);
end;
end;
end; begin
readln(n);
for i:= to n do
begin
for j:= to do
begin
read(ch);
if ch='' then a[i]:=a[i] or <<(j-);
end;
readln;
end;
while n> do
begin
if a[n]> then break;
dec(n);
end;
if n= then
begin
writeln();
halt;
end;
fillchar(f,sizeof(f),);
t[]:=;t[]:=;
ans:=maxlongint;
f[,]:=;
bfs;
writeln(ans);
end.

看样子我的代码在Pascal党里算是很短的了。。。而且我的代码还有饱受机房神犇吐槽的begin打在下一行,如下图,代码长度在最后一栏

[CodeVs1050]棋盘染色2(状态压缩DP)