如果发现广告等破坏行为,请尽量将条目恢复到较早的版本而不是把相应内容直接删除,谢谢合作。

URAL/1035

来自"NOCOW"

跳转到: 导航, 搜索

首先,定义线就为边,正面的边,为正边,反面的边为负边。对于一个连通块,对于某个顶点,设k=abs(正边数-负边数),说明在这个点上,以该顶点作为开始端点,或结束端点的的针数至少为k,设count为此连通块的k总和,如果count=0那么ans+1,否则ans+count div 2(因为一个是头,一个是尾所以要除以2),不懂的可以看刘汝佳的黑书P274。

{$M 655360}
program cao;
const
  maxn=210;
 
var
  d:array[0..maxn,0..maxn] of longint;
  visited,face1,face2,rear1,rear2:array[0..maxn,0..maxn] of boolean;
  a,b,c,e,f,g,h,i,j,k,l,n,m,p,q,count,ans:longint;
  ch:char;
 
procedure init;
begin
  readln(n,m);
  for i:=1 to n do
  begin
    for j:=1 to m do
    begin
      read(ch);
      if (ch=’X‘)or(ch=’\‘) then face1[i,j]:=true;
      if (ch=’X‘)or(ch=‘/’) then face2[i,j]:=true;
    end;
    readln;
  end;
  for i:=1 to n do
  begin
    for j:=1 to m do
    begin
      read(ch);
      if (ch=’X‘)or(ch=’\‘) then rear1[i,j]:=true;
      if (ch=’X‘)or(ch=‘/’) then rear2[i,j]:=true;
    end;
    readln;
  end;
end;
 
function search(i,j:longint):longint;
var
  t:longint;
begin
  if visited[i,j] then exit(0);
  visited[i,j]:=true;
  t:=d[i,j];
  if (face1[i,j])or(rear1[i,j]) then inc(t,search(i-1,j-1));
  if (face1[i+1,j+1])or(rear1[i+1,j+1]) then inc(t,search(i+1,j+1));
  if (face2[i,j+1])or(rear2[i,j+1]) then inc(t,search(i-1,j+1));
  if (face2[i+1,j])or(rear2[i+1,j]) then inc(t,search(i+1,j-1));
  exit(t);
end;
 
procedure main;
begin
  for i:=0 to n do
    for j:=0 to m do
    begin
      p:=0;
      q:=0;
      if face1[i,j] then inc(p);
      if face1[i+1,j+1] then inc(p);
      if face2[i,j+1] then inc(p);
      if face2[i+1,j] then inc(p);
      if rear1[i,j] then inc(q);
      if rear1[i+1,j+1] then inc(q);
      if rear2[i,j+1] then inc(q);
      if rear2[i+1,j] then inc(q);
      d[i,j]:=abs(p-q);
      if (p=0)and(q=0) then visited[i,j]:=true;
    end;
  ans:=0;
 
  for i:=0 to n do
    for j:=0 to m do
      if visited[i,j]=false then
      begin
        count:=search(i,j);
        if count=0 then
          inc(ans)
        else
          inc(ans,count shr 1);
      end;
end;
 
procedure print;
begin
  writeln(ans);
end;
 
begin
  init;
  main;
  print;
end.

华丽的分割线----------------------------------------------------------

饿,上面的标程好像在ural通不过去,会在第16个点栈溢出(stack overflow),仔细想想我认为是200*200的数据,dfs确实可能会导致系统栈溢出,所以我用了bfs来实现,通过了。基本思路一样。下面是我的程序(有点小乱)


const maxn=210;
type rr=record
      x,y:longint;
      end;
var ans,i,j,m,n,t,h,l:longint;
    len:array[0..maxn,0..maxn,0..3] of longint;
    p:array[0..maxn,0..maxn,0..8,0..3] of rr;
    bj:array[0..maxn,0..maxn] of boolean;
    c:char;
    dis:array[0..maxn,0..maxn] of longint;
    queue:array[1..maxn*maxn] of rr;
    father,sum:array[1..maxn*maxn] of longint;
 
    procedure dof(a:longint);
    begin
      inc(len[i,j+1,a]);
      p[i,j+1,len[i,j+1,a],a].x:=i+1;
      p[i,j+1,len[i,j+1,a],a].y:=j;
      inc(len[i+1,j,a]);
      p[i+1,j,len[i+1,j,a],a].x:=i;
      p[i+1,j,len[i+1,j,a],a].y:=j+1;
    end;
 
    procedure dos(a:longint);
    begin
      inc(len[i,j,a]);
      p[i,j,len[i,j,a],a].x:=i+1;
      p[i,j,len[i,j,a],a].y:=j+1;
      inc(len[i+1,j+1,a]);
      p[i+1,j+1,len[i+1,j+1,a],a].x:=i;
      p[i+1,j+1,len[i+1,j+1,a],a].y:=j;
    end;
 
    procedure bfs;
    var k,px,py:longint;
    begin
      repeat
        inc(h);
        px:=queue[h].x; py:=queue[h].y;
        for k:=1 to len[queue[h].x,queue[h].y,1] do
        if not bj[p[px,py,k,1].x,p[px,py,k,1].y] then
        begin
          inc(t);
          bj[p[px,py,k,1].x,p[px,py,k,1].y]:=true;
          father[t]:=h;
          queue[t]:=p[px,py,k,1];
        end;
        for k:=1 to len[queue[h].x,queue[h].y,2] do
        if not bj[p[px,py,k,2].x,p[px,py,k,2].y] then
        begin
          inc(t);
          bj[p[px,py,k,2].x,p[px,py,k,2].y]:=true;
          father[t]:=h;
          queue[t]:=p[px,py,k,2];
        end;
      until h=t;
    end;
begin
  //读入
  readln(n,m);
  fillchar(p,sizeof(p),0);
  fillchar(len,sizeof(len),0);
  for i:=1 to n do
  begin
    for j:=1 to m do
    begin
      read(c);
      if (c='/')or(c='X') then dof(1);
      if (c='\')or(c='X') then dos(1);
    end;
    readln;
  end;
 
  for i:=1 to n do
  begin
    for j:=1 to m do
    begin
      read(c);
      if (c='/')or(c='X') then dof(2);
      if (c='\')or(c='X') then dos(2);
    end;
    readln;
  end;
  //计算出每个点的正负边的差
  fillchar(bj,sizeof(bj),false);
  ans:=0;
  for i:=1 to n+1 do
  for j:=1 to m+1 do dis[i,j]:=abs(len[i,j,1]-len[i,j,2]);
  t:=0; h:=0;
  //利用bfs求连通块
  fillchar(father,sizeof(father),0);
  for i:=1 to n+1 do
  for j:=1 to m+1 do
  if (not bj[i,j])and(len[i,j,1]+len[i,j,2]<>0) then
  begin
    inc(t); queue[t].x:=i; queue[t].y:=j;
    bj[i,j]:=true;
    bfs;
  end;
  //计算
  ans:=0;
  for i:=t downto 1 do
  begin
    if father[i]=0 then
    begin
      l:=(dis[queue[i].x,queue[i].y]+sum[i]) div 2;
      if l=0 then inc(l);
      ans:=ans+l;
    end
    else sum[father[i]]:=sum[father[i]]+dis[queue[i].x,queue[i].y]+sum[i];
  end;
  writeln(ans);
end.    
                                                             by Brad-Vegetable
个人工具