错解:
设第$i$行上的值改变了$r1[i]$,第$j$列上的值改变了$r2[i]$
显然密码$(i,j,c)=r1[i]+r2[j]$
对于同一列上的两个密码$(i_{1},j,c_{1}),(i_{2},j,c_{2})$,它们的差值即为$c_{1}-c_{2}=r1[i_{1}]-r1[i_{2}]$
同一行上的同理。
这样我们就可以确定$r1[i],r2[j]$之间的关系,并以此判断
那么对于每组数据,我们可以$O(k^2)$两两枚举宝石,用上述方法判断即可。
同一个地方可能有两颗宝石
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cctype>
using namespace std;
void read(int &x){
char c=getchar();x=;bool f=;
while(!isdigit(c)) f=(f&&c!='-'),c=getchar();
while(isdigit(c)) x=(x<<)+(x<<)+(c^),c=getchar();
x=f?x:-x;
}
#define N 1005
int n,m,k,x[N],y[N],v[N],d1[N][N],d2[N][N];
bool w1[N][N],w2[N][N],ok;
int ask(int i,int j,int c){
if(c) return y[i]<y[j]?v[i]-v[j]:v[j]-v[i];
else return x[i]<x[j]?v[i]-v[j]:v[j]-v[i];
}
bool check(int i,int j){
if(x[i]==x[j]&&y[i]==y[j]&&v[i]!=v[j]) return ;//同个位置两颗宝石
if(y[i]==y[j]){
if(w1[x[i]][x[j]]&&d1[x[i]][x[j]]!=ask(i,j,)) return ;
d1[x[i]][x[j]]=d1[x[j]][x[i]]=ask(i,j,);
w1[x[i]][x[j]]=w1[x[j]][x[i]]=;
}
if(x[i]==x[j]){
if(w2[y[i]][y[j]]&&d2[y[i]][y[j]]!=ask(i,j,)) return ;
d2[y[i]][y[j]]=d2[y[j]][y[i]]=ask(i,j,);
w2[y[i]][y[j]]=w2[y[j]][y[i]]=;
}return ;
}
int main(){
int T;read(T);
while(T--){
memset(d1,,sizeof(d1));
memset(d2,,sizeof(d2));
memset(w1,,sizeof(w1));
memset(w2,,sizeof(w2));
read(n);read(m);read(k);ok=;
for(int i=;i<=k;++i)
read(x[i]),read(y[i]),read(v[i]);
for(int i=;i<=k&&ok;++i)
for(int j=i+;j<=k&&ok;++j)
ok=check(i,j);
printf(ok?"Yes\n":"No\n");
}return ;
}
上面这个做法被评论hack了
今天终于用差分约束过掉了
发现对于$(x1,y1,w1),(x2,y2,w2)$
如果$x1==x2$,那么可以得到$y1,y2$之间的操作差值$v[y1]-v[y2]=w1-w2$
于是通过这样在行和列分别建图
跑spfa判负环
记住多组数据,该清空的全清空掉
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define N 1005
#define M 2000005
int T,n,m,k,u[N],v[N],w[N],f1[N],f2[N];
bool vis1[N],vis2[N],ok; int Cnt1,hd1[N],nxt1[M],ed1[N],poi1[M],val1[M];
void adde1(int x,int y,int v){
nxt1[ed1[x]]=++Cnt1; hd1[x]=hd1[x]?hd1[x]:Cnt1;
ed1[x]=Cnt1; poi1[Cnt1]=y; val1[Cnt1]=v;
}
void link1(int x,int y,int v){adde1(x,y,v),adde1(y,x,-v);} int Cnt2,hd2[N],nxt2[M],ed2[N],poi2[M],val2[M];
void adde2(int x,int y,int v){
nxt2[ed2[x]]=++Cnt2; hd2[x]=hd2[x]?hd2[x]:Cnt2;
ed2[x]=Cnt2; poi2[Cnt2]=y; val2[Cnt2]=v;
}
void link2(int x,int y,int v){adde2(x,y,v),adde2(y,x,-v);} void spfa1(int x){
if(vis1[x]) ok=;
if(ok) return ;
vis1[x]=;
for(int i=hd1[x];i&&!ok;i=nxt1[i]){
int to=poi1[i];
if(f1[to]>f1[x]+val1[i])
f1[to]=f1[x]+val1[i],spfa1(to);
}
vis1[x]=;
}
void spfa2(int x){
if(vis2[x]) ok=;
if(ok) return ;
vis2[x]=;
for(int i=hd2[x];i&&!ok;i=nxt2[i]){
int to=poi2[i];
if(f2[to]>f2[x]+val2[i])
f2[to]=f2[x]+val2[i],spfa2(to);
}
vis2[x]=;
}
int main(){
scanf("%d",&T);
while(T--){
scanf("%d%d%d",&n,&m,&k);
f1[]=f2[]=ok=;
for(int i=;i<=n;++i) f1[i]=2e9;
for(int i=;i<=m;++i) f2[i]=2e9;
for(int i=;i<=n;++i) adde1(,i,);//虚拟源点建图,防止图不连通
for(int i=;i<=m;++i) adde2(,i,);
for(int i=;i<=k;++i){
scanf("%d%d%d",&u[i],&v[i],&w[i]);
for(int j=i-;j;--j){
if(v[i]==v[j]) link1(u[i],u[j],w[j]-w[i]);
if(u[i]==u[j]) link2(v[i],v[j],w[j]-w[i]);
}
}
spfa1(); spfa2();
puts(ok?"No":"Yes");
for(int i=;i<=n;++i) vis1[i]=hd1[i]=ed1[i]=;
for(int i=;i<=m;++i) vis2[i]=hd2[i]=ed2[i]=;
for(int i=;i<=Cnt1;++i) nxt1[i]=poi1[i]=;
for(int i=;i<=Cnt2;++i) nxt2[i]=poi2[i]=;
Cnt1=Cnt2=;
}return ;
}