[CodeVs1050]棋盘染色2(状态压缩DP)
Posted Sakits
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CodeVs1050]棋盘染色2(状态压缩DP)相关的知识,希望对你有一定的参考价值。
题目大意:有一个5*N(≤100)的棋盘,棋盘中的一些格子已经被染成了黑色,求最少对多少格子染色,所有的黑色能连成一块。
这题卡了我1h,写了2.6k的代码,清明作业一坨还没做啊。。。之前一直以为这题是插头DP,结果今天一看发现不用>_<,虽然还是状压DP。
因为只有5列,所以每行至多有3个黑色联通块,即黑,白,黑,白,黑,其他的情况都少于3个联通块了,所以我们可以把联通块标号。0表示白色,1表示1号联通块,2和3同理,所以我们可以用4进制来表示每一行的状态。则下一行的黑色若与上一行的黑色连接,它的联通块编号即上一行与其连接的黑色的联通块编号。对于每一个状态,枚举下一层要涂黑哪个白色,然后转移,最后一层所有黑色为同一联通块就更新答案。这样这道题就做完了,思路很简单,但是写起来确实有点麻烦。。。不过写那么久一定是我太弱了= =。。。
代码如下:
type
node=array[0..6]of longint;
var
f:array[0..100,0..2000]of longint;
a:array[0..100]of longint;
h:array[0..102400,1..2]of longint;
s,t:node;
ch:char;
n,i,j,ans:longint;
function lowbit(x:longint):longint;
begin
if x=0 then exit(0);
exit(lowbit(x-(x and -x))+1);
end;
procedure change(var a:node;sum1,sum2:longint);
var
i:longint;
begin
for i:=1 to 5 do
if a[i]=sum1 then
begin
a[i]:=sum2;
if (a[i-1]<>0)and(a[i-1]<10) then change(a,a[i-1],sum2);
if (a[i+1]<>0)and(a[i+1]<10) then change(a,a[i+1],sum2);
end;
end;
procedure work(var a:node);
var
i,sum:longint;
begin
sum:=10;
for i:=1 to 5 do
if (a[i]<>0)and(a[i]<10) then
begin
inc(sum);
change(a,a[i],sum);
end;
for i:=1 to 5 do
if a[i]>0 then dec(a[i],10);
end;
procedure bfs;
var
i,j,k,yy,front,rear:longint;
flag:boolean;
begin
h[1][1]:=0;h[1][2]:=0;
front:=0;rear:=1;
while front<rear do
begin
inc(front);
yy:=h[front][2];
for i:=1 to 5 do
begin
s[i]:=h[front][2] and 3;
h[front][2]:=h[front][2]>>2;
end;
h[front][2]:=yy;
if h[front][1]=n then
begin
flag:=true;
for i:=1 to 5 do
if s[i]>1 then flag:=false;
if flag then
if ans>f[h[front][1],h[front][2]] then ans:=f[h[front][1]][h[front][2]];
continue;
end;
for i:=0 to (1<<5)-1 do
if i and a[h[front][1]+1]=0 then
begin
for j:=1 to 5 do
t[j]:=(((a[h[front][1]+1]+i)>>(j-1))and 1)*(j+3);
k:=0;
for j:=1 to 5 do
if (s[j]>0) and (t[j]>0) then
begin
t[j]:=s[j];
k:=k or (1<<s[j]);
end;
flag:=true;
for j:=1 to 5 do
if (s[j]>0)and(k and (1<<s[j])=0) then flag:=false;
if flag=false then continue;
work(t);
k:=0;
for j:=5 downto 1 do
k:=k<<2+t[j];
if f[h[front][1]+1,k]>1000000000 then
begin
inc(rear);
h[rear][1]:=h[front][1]+1;
h[rear][2]:=k;
end;
if f[h[front][1]+1][k]>f[h[front][1]][h[front][2]]+lowbit(i) then
f[h[front][1]+1][k]:=f[h[front][1]][h[front][2]]+lowbit(i);
end;
end;
end;
begin
readln(n);
for i:=1 to n do
begin
for j:=1 to 5 do
begin
read(ch);
if ch=‘1‘ then a[i]:=a[i] or 1<<(j-1);
end;
readln;
end;
while n>0 do
begin
if a[n]>0 then break;
dec(n);
end;
if n=0 then
begin
writeln(0);
halt;
end;
fillchar(f,sizeof(f),63);
t[0]:=0;t[6]:=0;
ans:=maxlongint;
f[0,0]:=0;
bfs;
writeln(ans);
end.
看样子我的代码在Pascal党里算是很短的了。。。而且我的代码还有饱受机房神犇吐槽的begin打在下一行,如下图,代码长度在最后一栏
以上是关于[CodeVs1050]棋盘染色2(状态压缩DP)的主要内容,如果未能解决你的问题,请参考以下文章