1. 程式人生 > 實用技巧 >AT2033 【マス目と整數 / Grid and Integers】

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