POJ1683 Puzzlestan ——Floyd传递闭包+Dfs

好久没写Dfs了,拿来练手。

WA了一次,没有判断中间的情况……

解法:先用Floyd传递闭包处理哪些点一定要在一起、哪些点一定不能在一起,六重循环。

然后深搜,res[i][j]表示1,i这个物品在j这一行的匹配物品列编号。

没有最优性剪枝,只有一堆可能性剪枝:

(1)对于和(1,i)这个点关系为“一定在一起”的点(j,k),一定要将res[i,j]设置为k。

(2)即将搜索res[i][j]为k的情况是否可能,那么条件就要是(j,k)这个点与(1,i)点的关系不是“不可能在一起”,而且(j,k)这个点与所有已经和(1,i)点匹配的点的关系不是“不可能在一起”。

参考代码:

program poj1683;//By_Thispoet
const maxn=10;
var
  x1,y1,x2,y2        :longint;
  i,j,m,n,p,q,test   :longint;
  map                :array[0..maxn,0..maxn,0..maxn,0..maxn]of integer;
  res                :array[0..maxn,0..maxn]of integer;
  v                  :array[0..maxn,0..maxn]of boolean;
  ch                 :array[0..maxn,0..maxn]of char;
  c,cc               :char;
  flag               :boolean;

procedure printf();
begin
  for i:=1 to m do begin
    for j:=1 to n do write(ch[j,res[i,j]]);
    writeln;
  end;
  writeln;
end;

procedure dfs(code,pos:longint);var i,j,k:longint;begin
  if code=n+1 then begin
    printf();flag:=true;exit;
  end;
  if res[pos,code]<>-1 then begin
    if pos+1<=m then dfs(code,pos+1) else dfs(code+1,1);exit;
  end;
  if flag then exit;
  for i:=1 to m do if (not v[code][i])and(map[1,pos,code,i]<>2) then begin
    for j:=code+1 to n do for k:=1 to m do if (map[code,i,j,k]=1)and(res[pos,j]<>-1)then begin
      flag:=true;break;
    end;
    for j:=1 to code-1 do if map[code,i,j,res[pos,j]]=2 then begin
      flag:=true;break;
    end;
    if flag then begin flag:=false; continue; end;
    v[code][i]:=true;res[pos,code]:=i;
    for j:=code+1 to n do for k:=1 to m do if (map[code,i,j,k]=1) then begin
      res[pos,j]:=k;v[j,k]:=true;break;
    end;
    if pos+1<=m then dfs(code,pos+1) else dfs(code+1,1);
    if flag then exit;
    for j:=code+1 to n do for k:=1 to m do if map[code,i,j,k]=1 then begin
      res[pos,j]:=-1;v[j,k]:=false;break;
    end;
    v[code][i]:=false;res[pos,code]:=-1;
  end;
end;

begin
  readln(test);
  while test>0 do begin
    readln(n,m);filldword(map,sizeof(map)shr 2,0);
    fillchar(res,sizeof(res),255);
    for i:=1 to n do begin
      for j:=1 to m do read(ch[i][j]);readln;
    end;
    flag:=false;readln(x1,y1,cc,c,cc,x2,y2);
    while not (x1=0) do begin
      if c='R' then begin
        map[x1,y1,x2,y2]:=1;map[x2,y2,x1,y1]:=1;
      end else begin
        map[x1,y1,x2,y2]:=2;map[x2,y2,x1,y1]:=2;
      end;
      readln(x1,y1,cc,c,cc,x2,y2);
    end;
    for p:=1 to n do for q:=1 to m do
      for x1:=1 to n do for y1:=1 to m do
        for x2:=1 to n do for y2:=1 to m do
          begin
            if (map[x1,y1,p,q]=1)and(map[x2,y2,p,q]=2) then map[x1,y1,x2,y2]:=2;
            if (map[x1,y1,p,q]=2)and(map[x2,y2,p,q]=1) then map[x1,y1,x2,y2]:=2;
            if (map[x1,y1,p,q]=1)and(map[x2,y2,p,q]=1) then map[x1,y1,x2,y2]:=1;
          end;
    fillchar(v,sizeof(v),0);for i:=1 to m do res[i,1]:=i;
    for i:=1 to m do for p:=2 to n do for q:=1 to m do
      if map[1,i,p,q]=1 then begin res[i,p]:=q; v[p,q]:=true; end;
    dfs(1,1);
    dec(test);
  end;
end.

 

转载于:https://www.cnblogs.com/Thispoet/archive/2011/11/01/2232041.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值