P2198 [JZOJ/中山市市选] 简单数迷

给你一个矩阵,有一些格子有数字,有一些没有。没有数字的格子的个数 \(\leq 4^2\)。让你用 \(1\)~\(9\) 填满所有没有数字的格子,使得每一行每一列等于给出的它数字。

如:

首先我们知道如果直接暴力 \(9^{4^2}\) 的,肯定爆炸。

不过我们有自己的优化方式。

首先我们记录 \(rest_{i,1/2}\) 代表某一个行或者列还剩几个数字没有填,\(1\) 是行,\(2\) 是列。以及我们可以设一个 \(sum_{i,1/2}\) 代表某一行或列的现在的总和。其次,我们把所有空着的格子取出来,然后用队列存起来,就不用一个一个遍历。我们每一次 for i:=1 to 9 do 的时候设一个 \(front\)\(border\) 代表从几遍历到几,一开始 brder:=min(min(9,condition[x,1]),condition[y,2]); (\(condition\) 为限制),然后 if rest[x,1]=1 then border:=min(border,condition[x,1]-sum[x,1]); if rest[y,2]=1 then border:=min(border,condition[y,2]-sum[y,2]);
\(front\) 的修改也差不多,if (rest[x,1]=1)or(rest[y,2]=1) then front:=border;

数据太水,细节较多,压路机碾过。

Uses math;

Const
    total=11;

var
    sum,rest,condition:array[-1..total,1..2] of longint;
    bucket:array[-1..total,-1..total,1..2] of longint;
    ans,matrix:array[-1..total,-1..total] of longint;
    queue:array[-1..121,-1..2] of longint;
    i,j,n,m,way,tail,test:longint;
    bz,fuck:boolean;

procedure Dfs(now:longint);
var i,k,j,x,y,front,border:longint;
begin
    if fuck then exit;
    if now>tail then
    begin
        bz:=False;
        for i:=1 to n do if condition[i,1]<>sum[i,1] then begin bz:=True; break; end; if bz then exit;
        for i:=1 to m do if condition[i,2]<>sum[i,2] then begin bz:=True; break; end; if bz then exit;
        inc(way); if way=2 then begin writeln('Not unique.'); fuck:=True; exit; end;
        ans:=matrix; exit;
    end;
    x:=queue[now,1]; y:=queue[now,2]; border:=min(min(9,condition[x,1]),condition[y,2]);
    if rest[x,1]=1 then border:=min(border,condition[x,1]-sum[x,1]);
    if rest[y,2]=1 then border:=min(border,condition[y,2]-sum[y,2]);
    if border<=0 then exit; front:=1;
    if (rest[x,1]=1)or(rest[y,2]=1) then front:=border;
    for i:=border downto front do
    begin
        if (bucket[i,x,1]>0)or(bucket[i,y,2]>0) then continue;
        dec(rest[x,1]); dec(rest[y,2]); inc(sum[x,1],i); inc(sum[y,2],i);
        inc(bucket[i,x,1]); inc(bucket[i,y,2]);
        matrix[x,y]:=i; Dfs(now+1); matrix[x,y]:=0;
        dec(bucket[i,x,1]); dec(bucket[i,y,2]);
        inc(rest[x,1]); inc(rest[y,2]); dec(sum[x,1],i); dec(sum[y,2],i);
    end;
end;

procedure Work;
begin
    fillchar(condition,sizeof(condition),0);
    fillchar(bucket,sizeof(bucket),0);
    fillchar(matrix,sizeof(matrix),0);
    fillchar(queue,sizeof(queue),0);
    fillchar(rest,sizeof(rest),0);
    fillchar(sum,sizeof(sum),0);
    fillchar(ans,sizeof(ans),0);
    read(n,m); tail:=0; fuck:=False;
    for i:=1 to n do read(condition[i,1]);
    for i:=1 to m do read(condition[i,2]);
    for i:=1 to n do inc(rest[i,1],m);
    for i:=1 to m do inc(rest[i,2],n);
    for i:=1 to n do for j:=1 to m do
    begin
        read(matrix[i,j]);
        if matrix[i,j]=0 then begin inc(tail); queue[tail,1]:=i; queue[tail,2]:=j; end;
        if matrix[i,j]>0 then
            begin
                dec(rest[i,1]); dec(rest[j,2]);
                inc(bucket[matrix[i,j],i,1]); inc(bucket[matrix[i,j],j,2]);
            end;
    end;
    for i:=1 to n do for j:=1 to m do inc(sum[i,1],matrix[i,j]);
    for i:=1 to m do for j:=1 to n do inc(sum[i,2],matrix[j,i]);
    way:=0; Dfs(1); if fuck then exit;
    if way=0 then begin writeln('No answer.'); exit; end;
    for i:=1 to n do begin for j:=1 to m do write(ans[i,j],' '); writeln; end;
end;

begin
    assign(input,'kakuro.in');reset(input);
    assign(output,'kakuro.out');rewrite(output);
    read(test);
    while test>0 do begin Work; dec(test); end;
    close(input); close(output);
end.
posted @ 2019-04-15 12:52  _ARFA  阅读(185)  评论(0编辑  收藏  举报