AT2033 【マス目と整数 / Grid and Integers】

AT2033 【マス目と整数 / Grid and Integers】

题意

给定一个 $ R \times C $ 的矩阵,有一些位置的数已经被固定了,每个格子中只能有非负整数

 

询问是否有一种填数方案使得任意一个$ 2 \times 2 $ 的子矩阵中有对角线之和相等

 

题解

考虑化简题目要求
    
   $ a_{i,j} + a_{i+1,j+1} = a_{i+1,j} + a_{i,j+1} $
   
   $ a_{i,j} - a_{i,j+1} = a_{i+1,j+1} - a_{i+1,j+1} $

同理有

 $ a_{i,j} - a_{i+1,j} = a_{i,j+1} - a_{i+1,j+1} $

考虑构造 $ a_{i,j} = x_i + y_j $

如果存在可能的x序列和y序列

那么对于每个子矩阵限制条件一定满足

则原问题转化为给定一些形如 $ x_i + y_j = val_k $ 的限制,能否构造出符合条件的序列

显然任意两个 $x_i$ 之间都不影响 同理$y_i$也是

于是考虑连边,所成图一定是若干个个二分图

考虑给每个节点染色使得点权之和等于边权

按照套路,先尝试不考虑非负的限制,随便构造出一组方案

显然随便找一个点赋个权值进行染色即可,显然如果没有限制相互矛盾这样一定可以构造出一种方案

之后考虑调整一波,使得每个点非负,把每个二分图的搜索树画出来,容易发现对于一个点x,如果一个点增加了K,那么为了满足限制条件,所有点都会相应的加K或减K

所以只要在一种构造方案中有最小的 $x_i$ 和 $y_i$相加为非负数就一定有可行方案

代码很简单

#include<bits/stdc++.h>

using namespace std;

#define LL long long

inline LL read()
{
    LL f = 1,x = 0;
    char ch;
    do
    {
        ch = getchar();
        if(ch == '-') f = -1;
    }while(ch < '0'||ch > '9');
    do
    {
        x = (x<<3) + (x<<1) + ch - '0';
        ch = getchar();
    }while(ch >= '0' && ch <= '9');
    return f*x;
} 

const int MAXN = 100000 + 10;
 
int R,C;
int N;
bool vis[MAXN<<1];
vector<pair<int,LL> >G[MAXN<<1];
LL col[MAXN<<1];
int rt[MAXN<<1],tot;
vector<int>Sta[MAXN<<1];

inline bool dfs(int x)
{
    vis[x] = 1;
    Sta[tot].push_back(x);
    bool flag = 1;
    for(int i=0;i<G[x].size();i++)
    {
        LL v = G[x][i].first,w = G[x][i].second;
        if(vis[v]){ if(col[v] + col[x] != w) return false;}
        else
        {
            col[v] = w - col[x];
            flag &= dfs(v);
            if(!flag) return false;
        }
    }
    return flag;
}

inline bool check(int x)
{
    LL res1 = 1LL<<62,res2 = 1LL<<62;
    for(int i=0;i<Sta[x].size();i++)
    {
        int v = Sta[x][i];
        if(v > R) res2 = min(res2 , col[v]);
        else res1 = min(res1, col[v]);
    }
    return res1 + res2 >= 0;
}

int main()
{
    R = read(),C = read();
    N = read();
    for(int i=1;i<=N;i++)
    {
        int x = read(),y = read(),w = read();
        G[x].push_back(make_pair(y+R,w));
        G[y+R].push_back(make_pair(x,w));
    }
    bool flag = 1;
    for(int i=1;i<=R+C;i++) if(!vis[i]) rt[++tot] = i,col[i] = 0,flag &= dfs(i);
    if(!flag) { printf("No\n");return 0;}
    for(int i=1;i<=tot;i++) flag &= check(i);
    if(!flag) printf("No\n");
    else printf("Yes\n"); 
 } 

 

posted @ 2020-11-19 16:32  wlzs1432  阅读(111)  评论(0编辑  收藏  举报