poj 1795 DNA Laboratory 状压dp

题意:给出 n (n ≤15 ) 个字符串,求一个最短的串 S ,使得给出的那些串都是 S 的子
串。如果有多个解输出字典序最小的一个。

这题写的我快哭出来了55555555555

先说一下我写这道题的经历吧。一开始很容易就想到用f[i,j]表示状态i以j结尾时的最短长度,然后我用了一个f1数组来记录字符串,然后发现MLE……接着便把f1数组去掉,但冥思苦想都想不到一种优美的方法来找答案。弱渣的BPM表示可以用dp来搞,但我感觉太麻烦,于是BPM又告诉我说可以把f[i,j]改为状态为i且j为开头时的最短长度,这样可以贪心结果并维护字典序,然后我便改了……结果发现不管怎么搞都是WA……最后仍是BPM告诉我,若某一个字符串是另一个的子串,则要把该串去掉,不然就会WA……

最后AC出来的那一刻,感觉整个人生都圆满了!!!

突然想起题解已经全在上面了。

代码:

var
  t,l,i,j,k,a1,x,last,n,ans,m:longint;
  w:array[0..15] of longint;
  s:array[0..15] of ansistring;
  len,a,b:array[0..15] of longint;
  g:array[0..15,0..15] of longint;
  f:array[0..60000,1..15] of longint;
  anss:ansistring;

function min(x,y:longint):longint;
begin
  if x<y then exit(x)
         else exit(y);
end;

procedure sort;
var
  i,j:longint;
begin
  for i:=1 to n-1 do
    for j:=i+1 to n do
      if s[i]>s[j] then
      begin
        s[0]:=s[i];s[i]:=s[j];s[j]:=s[0];
        len[0]:=len[i];len[i]:=len[j];len[j]:=len[0];
      end;
end;

function work(x:longint):longint;
begin
  work:=0;
  while x>0 do
  begin
    inc(work);
    x:=x div 2;
  end;
end;

procedure dfs(x,d:longint);
var
  u:longint;
  i,min:longint;
  mins:ansistring;
begin
  if x=0 then exit;
  mins:='';
  for i:=1 to n do
    if f[x,i]-g[w[d-1],i]=ans then
    begin
      if (mins='')or(anss+copy(s[i],g[w[d-1],i]+1,len[i]-g[w[d-1],i])<mins) then
      begin
        mins:=anss+copy(s[i],g[w[d-1],i]+1,len[i]-g[w[d-1],i]);
        u:=i;
      end;
    end;
  w[d]:=u;
  anss:=mins;
  ans:=ans-len[u]+g[w[d-1],u];
  dfs(x-(1 shl (u-1)),d+1);
end;

procedure sort1;
var
  i,j:longint;
begin
  for i:=1 to n-1 do
    for j:=i+1 to n do
      if len[i]>len[j] then
      begin
        s[0]:=s[i];s[i]:=s[j];s[j]:=s[0];
        len[0]:=len[i];len[i]:=len[j];len[j]:=len[0];
      end;
end;

begin
  readln(t);
  for l:=1 to t do
  begin
    readln(n);
    for i:=1 to n do
    begin
      readln(s[i]);
      len[i]:=length(s[i]);
    end;
    sort1;
    m:=0;
    for i:=1 to n-1 do
      for j:=i+1 to n do
        for k:=1 to len[j]-len[i]+1 do
          if copy(s[j],k,len[i])=s[i] then
          begin
            s[i]:='Z'+s[i];
            inc(m);
            break;
          end;
    sort;
    n:=n-m;
    fillchar(g,sizeof(g),0);
    for i:=1 to n do
      for j:=1 to n do
        if i<>j then
          for k:=min(len[i],len[j]) downto 1 do
            if copy(s[i],len[i]-k+1,k)=copy(s[j],1,k) then
            begin
              g[i,j]:=k;
              break;
            end;
    fillchar(f,sizeof(f),$7f div 3);
    for i:=1 to n do
      f[1 shl (i-1),i]:=len[i];
    for i:=1 to 1 shl n-1 do
    begin
      x:=i;
      a1:=0;
      while x>0 do
      begin
        inc(a1);
        a[a1]:=x and -x;
        x:=x-x and -x;
        b[a1]:=work(a[a1]);
      end;
      for j:=1 to a1 do
        for k:=1 to a1 do
          if j<>k then
            if f[i-a[j],b[k]]-g[b[j],b[k]]+len[b[j]]<f[i,b[j]] then
              f[i,b[j]]:=f[i-a[j],b[k]]+len[b[j]]-g[b[j],b[k]];
    end;
    anss:='';
    ans:=maxlongint;
    for i:=1 to n do
      if f[1 shl n-1,i]<ans then ans:=f[1 shl n-1,i];
    dfs(1 shl n-1,1);
    writeln('Scenario #',l,':');
    writeln(anss);
    writeln;
  end;
end.


你可能感兴趣的:(poj 1795 DNA Laboratory 状压dp)