01串变换问题

题目大意:给你一些操作(操作和串的长度一样,操作的每一位对应串的每一位),一些串和它的目标串,求出把它变换成目标串的最小操作次数。

串的长度len<=20,操作方式m<=50,n<=4

考虑到直接枚举所有操作并且每次对每一位进行操作会很慢,又都是01串,很容易想到位运算。

把每一个串都看成一个二进制数,修改为1等价于or 1,修改为0为and 0,取反为xor 1。

所以建立三个数组,c0,c1,cqf表示三种运算,一个操作则对应三个二进制数。

这样状态就可以O(1)的转移。

program Neayo;
const
        inf='quantum.in';
        ouf='quantum.out';
var
   i,j,k,len,now,target,min,m,n:longint;
   a:array[0..4]of longint;
   c0,c1,cqf:array[0..51]of longint;
   h:array[0..2097152] of boolean;
   q,qt:array[0..1000000]of longint;
procedure bfs;
var i,tmp,time,top,closed:longint;
begin
     time:=0; top:=0;closed:=1;q[1]:=now;qt[1]:=0;
     repeat
           inc(top);
           if top>1000000 then top:=1;
           now:=q[top];
           for i:=1 to m do
           begin
                tmp:=now and c0[i];
                tmp:=tmp or c1[i];
                tmp:=tmp xor cqf[i];
                inc(time);
                if not h[tmp] then
                begin
                     h[tmp]:=true;
                     inc(closed);
                     if closed>1000000 then closed:=1;
                     q[closed]:=tmp;
                     qt[closed]:=qt[top]+1;
                     if qt[closed]=6 then
                     closed:=closed;
                     if tmp=target then
                     begin
                          writeln(qt[closed]);
                          exit;
                     end;
                end;
           end;
     until(h[target] or (time>100000000000)or (top>=closed));
     writeln('NP');
end;
procedure init;
var
    s:string;
begin
     assign(input,inf);assign(output,ouf);
     reset(input);rewrite(output);
     readln(len,m,n);
     for i:=1 to m do
     begin
          readln(s);
          for j:=1 to len do
          begin
               if s[j]<>'C'then c0[i]:=c0[i]+(1 shl (len-j));
               if s[j]='S' then c1[i]:=c1[i]+(1 shl (len-j));
               if s[j]='F' then cqf[i]:=cqf[i]+(1 shl (len-j));
          end;
     end;
     for i:=1 to n do
     begin
          fillchar(h,sizeof(h),false);
          readln(s);
          now:=0;target:=0;
          for j:=1 to len do
           if s[j]='1' then now:=now+(1 shl (len-j));
          delete(s,1,len+1);
          for j:=1 to len do
           if s[j]='1' then target:=target+(1 shl (len-j));
          if now=target then
          begin
               writeln(0);
               continue;
          end;
          h[now]:=true;
          bfs;
     end;
     close(input);
end;
begin
     init;
     close(output);
end.                                          

 

转载于:https://www.cnblogs.com/neayo/archive/2012/10/12/2721417.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值