poj 2185 Milking Grid KMP算法

题目:给出一个矩阵,问是否有一个最小的矩阵是的重复多次该矩阵后可以得到原矩阵(不一定平铺后恰好可以得到整个矩形网格而不多出一部分),求该矩阵的面积。

分析:对于长度为l的一个串s[i],显然l-next[l],l-next[next[l]],…都是能通过复制,完全覆盖字符串的可行串,用get_next得到所有可行的方案。对所有s[i]都可行的最小的划分方案即为最终的宽度w。至于矩阵的高度h,只需要把每个s[i]的前w个字符当作一个正题,记作w[i],对w[1],w[2],…做get_next,得到竖着的最小重复“子串”,即为高h。

下面附程序:

var
  n,m,i,j,h,w:longint;
  flag:boolean;
  v:array[1..10000,1..75] of boolean;
  next:array[0..10000] of longint;
  a:array[1..10000,1..75] of char;

procedure get1(x:longint);
var
  i,j:longint;
begin
  next[0]:=-1;
  next[1]:=0;
  i:=2;
  j:=0;
  while i<=m do
    if (j=-1)or(a[x,i]=a[x,j+1])
      then begin
             inc(j);
             next[i]:=j;
             inc(i);
           end
      else j:=next[j];
end;

procedure get2(x:longint);
var
  i,j:longint;
begin
  next[0]:=-1;
  next[1]:=0;
  i:=2;
  j:=0;
  while i<=n do
    if (j=-1)or(a[j+1,x]=a[i,x])
      then begin
             inc(j);
             next[i]:=j;
             inc(i);
           end
      else j:=next[j];
end;

begin
  readln(n,m);
  for i:=1 to n do
    for j:=1 to m do
      if j<m
        then read(a[i,j])
        else readln(a[i,j]);
  fillchar(v,sizeof(v),false);
  for i:=1 to n do
  begin
    v[i,m]:=true;
    get1(i);
    j:=next[m];
    while j>0 do
    begin
      v[i,m-j]:=true;
      j:=next[j];
    end;
  end;
  for i:=1 to m do
  begin
    flag:=true;
    for j:=1 to n do
      if not v[j,i] then
      begin
        flag:=false;
        break;
      end;
    if flag then
    begin
      w:=i;
      break;
    end;
  end;
  fillchar(v,sizeof(v),false);
  for i:=1 to w do
  begin
    v[n,i]:=true;
    get2(i);
    j:=next[n];
    while j>0 do
    begin
      v[n-j,i]:=true;
      j:=next[j];
    end;
  end;
  for i:=1 to n do
  begin
    flag:=true;
    for j:=1 to w do
      if not v[i,j] then
      begin
        flag:=false;
        break;
      end;
    if flag then
    begin
      h:=i;
      break;
    end;
  end;
  writeln(h*w);
end.


你可能感兴趣的:(poj 2185 Milking Grid KMP算法)