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"); }