bzoj 4500 矩阵 题解

题意:
有一个 $ n * m $ 的矩阵,初始每个格子的权值都为 $ 0 $,可以对矩阵执行两种操作:

  1. 选择一行,该行每个格子的权值加1或减1。
  2. 选择一列,该列每个格子的权值加1或减1。

现在有 $ K $ 个限制,每个限制为一个三元组 $ (x,y,c) $ ,代表格子$ (x,y) $ 权值等于 $ c $ 。问是否存在一个操作序列,使得操作完后的矩阵满足所有的限制。如果存在出” $ Yes $ ”,否则输出” $ No $ ”。

这道题是个一个查分约束题,它给出 $ K $ 个条件要求即$ (x,y) $ 的权值为 $ c $ 我们可以看作 $ x $ 行的变换量 $ add[x] $ ,与第 $ y $ 列的变化量 $ add[y] $ 的和等于 $ c $ ,由于我们设置的是变化量所以是正还是负就无所谓~,所以我们可以写出 $ add[x]+add[y]=c $

等价于 $ add[y]-(-add[x])=c $

等价于 $ add[y]-(-add[x]) \geq c $ && $ add[y]-(-add[x]) \leq c $

等价于 $ add[y]-add[x]^\geq c $ && $ add[x]^-add[y] \geq -c $

然后就可以由 $ x->y $ 连一条长为 $ c $ 的边,由 $ y->x $ 连一条长为 $ -c $ 的边

至于为啥

由于列与行要区分,那么令列加上 $ n $ 即可

代码

#include<bits/stdc++.h>
using namespace std;
const int size=2010;
int head[size],Next[2*size],ver[2*size],edge[2*size],deg[size],tot;
int v[size],dis[size];
int n,m,k,T;
queue<int>q;
inline int read(){
   int x=0,f=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){
       if(ch=='-')
           f=-1;
       ch=getchar();
   }
   while(ch>='0'&&ch<='9'){
       x=(x<<1)+(x<<3)+(ch^48);
       ch=getchar();
   }
   return x*f;
}
void add(int x,int y,int z){
   ver[++tot]=y;edge[tot]=z;Next[tot]=head[x];head[x]=tot;
}
bool spfa(){
   while(q.size()) q.pop();
   memset(v,0,sizeof(v));
   memset(deg,0,sizeof(deg));
   memset(dis,0x3f,sizeof(dis));
   dis[0]=0;v[0]=1;q.push(0);
   while(q.size()){
       int x=q.front();q.pop();v[x]=0;
       if(deg[x]==n+m-1) return 0;
       deg[x]++;
       for(int i=head[x];i;i=Next[i]){
           int y=ver[i];
           if(dis[y]>dis[x]+edge[i]){
               dis[y]=dis[x]+edge[i];
               if(!v[y]){
                   v[y]=1;
                   q.push(y);
               }
           }
       }
   }
   return 1;
}
int main(){
   scanf("%d",&T);
   while(T--){
       memset(head,0,sizeof(head));tot=0;
       n=read();m=read();k=read();
       for(int i=1;i<=k;++i){
           int x,y,z;
           x=read();y=read();z=read();
           add(x,y+n,z);
           add(y+n,x,-z);
       }
       for(int i=1;i<=n+m;++i){
           add(0,i,0);
       }
       if(spfa()) printf("Yes\n");
       else printf("No\n");
   }
   return 0;
}

猜你喜欢

转载自www.cnblogs.com/donkey2603089141/p/11819115.html