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