#差分约束系统#CodeChef Digit Matrix&洛谷 7515 [省选联考 2021 A 卷] 矩阵游戏
分析
先任意构造出一个不一定满足值域的矩阵,现在只需要满足值域就可以了。
可以发现,给一行或一列依次加一减一2*2矩阵的和仍然不变,并且如果有解一定能构造出一组方案。
因为第一行和第一列如果确定,所以只要通过这样的加一减一,其它位置就能确定。
设行的选择为 \(dx[i]\),列的选择为 \(dy[j]\),那么就要满足 \(0\leq a[i][j]+dx[i]+dy[j]\leq 10^6\)
可是这样的加法好像也挺难做的,能不能强制让一个为加,一个为减,这是可行的,将矩阵黑白染色。
如果 \(i\) 和 \(j\) 奇偶性不同,那么 \(dy[j]-dx[i]\leq M-a[i][j],dx[i]-dy[j]\leq a[i][j]\),
同奇同偶的情况正好将 \(dx[i]\) 和 \(dy[j]\) 调换即可,跑一遍最短路如果有负环那么无解,否则同样按照奇偶性输出方案即可。
代码(矩阵游戏)
#include <cstdio>
#include <cctype>
#include <deque>
#define rr register
using namespace std;
const int N=301,M=1000000; deque<int>q;
struct node{int y,w,next;}e[N*N<<1]; long long dis[N<<1];
int cnt[N<<1],et,as[N<<1],v[N<<1],a[N][N],n,m,flag;
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
inline void add(int x,int y,int w){
e[++et]=(node){y,w,as[x]},as[x]=et;
}
signed main(){
for (rr int T=iut();T;--T){
n=iut(),m=iut(),et=0;
for (rr int i=1;i<=n+m;++i) dis[i]=1e15;
for (rr int i=1;i<=n+m;++i) as[i]=cnt[i]=v[i]=0;
for (rr int i=1;i<n;++i)
for (rr int j=1;j<m;++j) a[i][j]=iut();
for (rr int i=n-1;i;--i)
for (rr int j=m-1;j;--j)
a[i][j]-=a[i+1][j]+a[i][j+1]+a[i+1][j+1];
for (rr int i=1;i<=n;++i)
for (rr int j=1;j<=m;++j)
if ((i+j)&1) add(i,j+n,M-a[i][j]),add(j+n,i,a[i][j]);
else add(i,j+n,a[i][j]),add(j+n,i,M-a[i][j]);
while (!q.empty()) q.pop_back();
q.push_back(1),dis[1]=0,v[1]=flag=1;
while (!q.empty()&&flag){
rr int x=q.front(); q.pop_front();
if (++cnt[x]==n+m) {flag=0; break;}
for (rr int i=as[x];i;i=e[i].next)
if (dis[e[i].y]>dis[x]+e[i].w){
dis[e[i].y]=dis[x]+e[i].w;
if (!v[e[i].y]){
v[e[i].y]=1;
if (!q.empty()&&dis[e[i].y]<dis[q.front()])
q.push_front(e[i].y);
else q.push_back(e[i].y);
}
}
v[x]=0;
}
if (!flag) printf("NO\n");
else{
printf("YES\n");
for (rr int i=1;i<=n;++i)
for (rr int j=1;j<=m;++j){
if ((i+j)&1) print(a[i][j]-dis[i]+dis[j+n]);
else print(a[i][j]+dis[i]-dis[j+n]);
putchar(j==m?10:32);
}
}
for (rr int i=1;i<=n;++i)
for (rr int j=1;j<=m;++j) a[i][j]=0;
}
return 0;
}
代码(DGMATRIX)
#include <cstdio>
#include <cctype>
#include <deque>
using namespace std;
const int N=111,M=9; deque<int>q;
struct node{int y,w,next;}e[N*N<<1];
int et,as[N<<1],v[N<<1],dis[N<<1],a[N][N],n,m;
int iut(){
int ans=0; char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
void add(int x,int y,int w){
e[++et]=(node){y,w,as[x]},as[x]=et;
}
int main(){
n=iut()+1;
for (int i=1;i<=n*2;++i) dis[i]=0x3f3f3f3f;
for (int i=1;i<n;++i)
for (int j=1;j<n;++j) a[i][j]=iut();
for (int i=n-1;i;--i) for (int j=n-1;j;--j)
a[i][j]-=a[i+1][j]+a[i][j+1]+a[i+1][j+1];
for (int i=1;i<=n;++i)
for (int j=1;j<=n;++j)
if ((i+j)&1) add(i,j+n,M-a[i][j]),add(j+n,i,a[i][j]);
else add(i,j+n,a[i][j]),add(j+n,i,M-a[i][j]);
q.push_back(1),dis[1]=0,v[1]=1;
while (!q.empty()){
int x=q.front(); q.pop_front();
for (int i=as[x];i;i=e[i].next)
if (dis[e[i].y]>dis[x]+e[i].w){
dis[e[i].y]=dis[x]+e[i].w;
if (!v[e[i].y]){
v[e[i].y]=1;
if (!q.empty()&&dis[e[i].y]<dis[q.front()])
q.push_front(e[i].y);
else q.push_back(e[i].y);
}
}
v[x]=0;
}
for (int i=1;i<=n;++i){
for (int j=1;j<=n;++j)
if ((i+j)&1) putchar(48+a[i][j]-dis[i]+dis[j+n]);
else putchar(48+a[i][j]+dis[i]-dis[j+n]);
putchar(10);
}
return 0;
}