zoukankan      html  css  js  c++  java
  • [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.
    View Code

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

  • 相关阅读:
    Java 实现 HDFS 文件基本操作
    [git] branch 分支操作
    Java基本语法-----java流程控制语句
    Java基本语法-----java运算符的优先级与结合性
    Java基本语法-----java数据类型的转换
    CSDN发表文章后老是待审核的原因
    Java基本语法-----java变量
    Java基本语法-----java进制的转换
    Java基本语法-----java常量
    Java基本语法-----java注释
  • 原文地址:https://www.cnblogs.com/Sakits/p/5350153.html
Copyright © 2011-2022 走看看