【BZOJ4500】矩阵

题面

http://darkbzoj.tk/problem/4500

题解

首先,一行或者一列,又加又减肯定是没有意义的,所以相当于每一行每一列都有一个值,交点的值等于它们相加。

设$dis[i] (1<=i<=n)$的含义为第$i$行加的值(可正可负)

$dis[n+j] (1<=j<=m)$的含义为第$j$列加的值的相反数(同上)

然后写成作差的形式,初一的$hxh$(话说$hxh$跟我现在的班主任$wsy$长得真像。。。。)告诉我们,减负数等于加正数,就是一个等式,可以用差分约束做,但是因为都是等式取到等号,所以直接用$dfs$判$dis$值是否满足每一条边的需求就可以了。

(这可能就是$zhhx$说的把每个点看做变量,方程看做一个边的典型例题?终于找到了)

#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 2050
#define ri register int
#define INF 1000000007
using namespace std;

inline int read() {
  int ret=0,f=0; char ch=getchar();
  while (ch<'0' || ch>'9') f|=(ch=='-'),ch=getchar();
  while (ch>='0' && ch<='9') ret*=10,ret+=(ch-'0'),ch=getchar();
  return f?-ret:ret;
}

int n,m,k,dis[N];
bool can=0;
vector<int> to[N],len[N];

void clear() {
  memset(dis,0x3f,sizeof(dis));
  for (ri i=1;i<=n+m;i++) to[i].clear(),len[i].clear();
}
void add_edge(int u,int v,int l) {
  to[u].push_back(v); len[u].push_back(l);
}

bool dfs(int x) {
  for (ri i=0;i<to[x].size();i++) {
    int y=to[x][i];
    if (dis[y]>INF) {
      dis[y]=dis[x]+len[x][i];
      if (!dfs(y)) return 0;
    }
    else {
      if (dis[y]!=dis[x]+len[x][i]) return 0;
    }
  }
  return 1;
}

bool check() {
  for (ri i=1;i<=n+m;i++) if (dis[i]>INF) {
    dis[i]=0;
    if (!dfs(i)) return 0;
  }
  return 1;
}

int main() {
  int T=read();
  while (T--) {
    n=read(); m=read(); k=read();
    clear();
    for (ri i=1;i<=k;i++) {
      int x=read(),y=read(),c=read();
      add_edge(x,y+n,c);
      add_edge(y+n,x,-c);
    }
    puts(check()?"Yes":"No");
  }
  return 0;
}

 

posted @ 2019-08-08 21:38  HellPix  阅读(234)  评论(2编辑  收藏  举报