题意:n*m的网格,初始为0.有两种操作:(1)把某一行全+1 (2)把某一列全+1 ,对其中m个格子有要求:(xi,yi)格子里的数是ci。问通过两种操作是否可以同时满足m个格子的要求,可以的话输出‘Yes’否则输出‘No’
(xi,yi)格子里的数是ci 对操作的限制其实是 这个格子必须被修改i次 即 第i行和第j列必须一共被修改ci次
我们用xi表示在满足要求时,第i行的操作次数(是个未知数);
yi表示在满足要求时,第i列的操作次数(是个未知数)
那么,我们通过m个限制就得到了m个等式,我们的问题就变成了这个等式组是否有解
一个naive的想法就是把这m个等式变成2*m个等价的不等式,然后利用差分约束系统来建图判断解的存在性
但是,会发现,我们的得到的等式的形式是 xi+yj=c 的形式,如果利用差分约束系统的思想,xi和yi作为点,c作为边权的话,我们是无法将它变成差分约束系统的标准形式的(-yj 是什么鬼)
那么我们考虑,究竟什么样的限制是会导致无解的,什么样的形式才可以变化成标准的差分约束系统
对于第xi行,它和多个列有不同的限制,而当这些列的限制冲突的时候就无解,对于列同理。
同时,对于我们得到的等式组,如果等号的左边是减法的话,我们就可以很轻易的变成标准形式
所以,其实真正会影响解的存在性的限制并不是第i行和第j列,而是和第i行同时有限制的列之间的关系、和第j列同时有限制的行之间的关系,如果这些关系能够同时满足就有解
所以对于行相同的 xi+yj=c1 ① xi+yk=c2 ②
我们用①-②,得到yj-yk=c1-c2 即 yj-yk<=c1-c2 且 yk-yj<=c2-c1
对于列相同的同理
这样我们就建图判断是否有负环即可
var
t,n,m,k,l :longint;
flag :boolean;
i,j :longint;
last,dis :array[0..2010] of longint;
pre,other,len :array[0..2000010] of longint;
vis :array[0..2010] of boolean;
x,y,z :array[0..1010] of longint;
procedure connect(x,y,z:longint);
begin
inc(l);
pre[l]:=last[x];
last[x]:=l;
other[l]:=y;
len[l]:=z;
end;
procedure dfs(x:longint);
var
p,q:longint;
begin
if flag then exit;
vis[x]:=true;
q:=last[x];
while (q<>0) do
begin
if flag then exit;
p:=other[q];
if (dis[p]>dis[x]+len[q]) then
begin
dis[p]:=dis[x]+len[q];
if vis[p] then
begin
flag:=true;
exit;
end else dfs(p);
end;
q:=pre[q];
end;
vis[x]:=false;
end;
procedure check;
begin
fillchar(dis,sizeof(dis),0);
fillchar(vis,sizeof(vis),false);
flag:=false;
for i:=1 to n+m do
begin
dfs(i);
if flag then exit;
end;
end;
begin
read(t);
while (t>0) do
begin
dec(t);
read(n,m,k);
l:=0; flag:=false;
fillchar(last,sizeof(last),0);
for i:=1 to k do read(x[i],y[i],z[i]);
for i:=1 to k do
for j:=i+1 to k do
begin
if flag then break;
if (x[i]=x[j]) and (y[i]=y[j]) and (z[i]<>z[j]) then
begin
flag:=true; break;
end;
if (x[i]=x[j]) and (y[i]<>y[j]) then
begin
connect(n+y[i],n+y[j],z[j]-z[i]);
connect(n+y[j],n+y[i],z[i]-z[j]);
end else
if (x[i]<>x[j]) and (y[i]=y[j]) then
begin
connect(x[i],x[j],z[j]-z[i]);
connect(x[j],x[i],z[i]-z[j]);
end;
end;
if not flag then check;
if not flag then writeln('Yes') else writeln('No');
end;
end.
——by Eirlys