BZOJ4500矩阵

Description

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

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

Input

先输入一个T(T <= 5)代表输入有T组数据,每组数据格式为:
第一行三个整数n, m, k (1 <= n, m,k <= 1000)。
接下来k行,每行三个整数x, y, c。

Output

对于每组数据,输出Yes或者No。

Sample Input

2

2 2 4

1 1 0

1 2 0

2 1 2

2 2 2

2 2 4

1 1 0

1 2 0

2 1 2

2 2 1

Sample Output

Yes

No

题解

用Xi表示第i行的操作,Yj表示第j列的操作,对于(i,j,c)就有Xi+Yj=c

c<=Xi+Yj<=c-->(-Yj)+c<=Xi     Xi-c<=(-Yj)

再用spfa跑最长路判负环即可,注意一开始将所有点放入队列,防止有些点不能遍历到

纯属口胡,因为没有权限交不了

#include<bits/stdc++.h>
using namespace std;

const int maxn=2005;
int t,n,m,k;
int cnt,head[maxn],cx[maxn];
struct edge{
    int y,val,next;
}e[maxn<<1];

void add(int x,int y,int z){
    e[++cnt]=(edge){y,z,head[x]};
    head[x]=cnt;
}

int dis[maxn];
queue<int> q;
bool vis[maxn];

bool spfa(){
    while(!q.empty()) q.pop();
    for(int i=1;i<=n+m;i++) q.push(i),dis[i]=0,cx[i]=1,vis[i]=true;
    while(!q.empty()){
        int x=q.front();
        q.pop();
        vis[x]=false;
        if(cx[x]>=n+m) return true;
        for(int i=head[x];i;i=e[i].next){
            int y=e[i].y,val=e[i].val;
            if(dis[y]<dis[x]+val){
                dis[y]=dis[x]+val;
                if(!vis[y]){
                    q.push(y);vis[y]=true;
                    if(++cx[y]>=n+m) return true;
                }
            }
        }
    }
    return false;
}

void nice(){
    cnt=0;
    memset(head,0,sizeof(head));
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=k;i++){
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        //z<=x+y<=z
        //z<=x-(-y)<=z
        //(-y)+z<=x    x-z<=(-y)
        add(y+n,x,z);add(x,y+n,-z);
    }
    printf("%s\n", spfa() ? "No" : "Yes" );
}

int main(){
    scanf("%d",&t);
    while(t--) nice();
}
View Code

 

posted @ 2019-07-18 17:39  _JSQ  阅读(198)  评论(0编辑  收藏  举报