题目链接:
https://codeforces.com/problemset/problem/1438/C
题目大意:
给你一个n*m的矩阵a,每个位置一个数字,现在你可以对每一个位置进行一次操作,
使得这个位置的数字+1或者不变,问你在对所有位置进行完之后,能否使矩阵没有任
意两个相邻个数字相同(上下左右)
输入与输出:
input:
第一行一个t,t组数据
每组数据第一行n m
然后n行m列代表给你的矩阵
output:
题目保证输入的矩阵一定有解,请输出任意一个经过操作后,合法的矩阵
思路:
对于每个位置的数字,它要么+1,要么不+1,并且其+1与否会影响到起相邻位置数字是否强制+1或者强制不+1
那么很容易想到2-SAT,把矩阵中每个数字抽象成两个点:其+1,其不+1
然后看其(设为x)上下左右如果有相等的数(设为y)则:
1. x+1->!(y+1)
y+1->!(x+1)
2. !(x+1)->y+1
!(y+1)->x+1
还有如果其上下左右有比其刚好大1的数字:
1. x+1->y+1
!(y+1)->!(x+1)
最后对于每个点每次输出tarjan缩点编号小的决策
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 105;
const int maxm = 2 * maxn * maxn;
int dx[][2] = { {1, 0}, {-1,0 },{0,1},{0,-1} };
int xx[maxn][maxn];
int n, m;
vector<vector<int>> vec(maxm);
int dfn[maxm];
int stk[maxm];
int low[maxm];
int scc[maxm];
bool vis[maxm];
int stkID;
int cntDN;
int totSC;
inline void getIDbyINF(int &id, int x, int y, bool cc);
void addedge(int id1, int id2);
void dfs(int ii)
{
dfn[ii] = ++cntDN;
low[ii] = dfn[ii];
stk[++stkID] = ii;
vis[ii] = 1;
for (int i = 0; i < vec[ii].size(); i++) {
int e = vec[ii][i];
if (!dfn[e]) {
dfs(e);
low[ii] = min(low[ii], low[e]);
}
else if(vis[e]) low[ii] = min(low[ii], low[e]);
}
if (dfn[ii] == low[ii]) {
int x;
totSC++;
do {
x = stk[stkID];
stkID--;
scc[x] = totSC;
vis[x] = 0;
} while (x != ii);
}
}
int main()
{
int t;
scanf("%d", &t);
while (t--) {
memset(dfn, 0, sizeof(dfn));
for (int i = 0; i < maxm; i++)
vec[i].clear();
cntDN = 0;
totSC = 0;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
scanf("%d", &xx[i][j]);
for(int i = 1;i <= n;i++)
for (int j = 1; j <= m; j++) {
int id00, id01;
getIDbyINF(id00, i, j, 0);
getIDbyINF(id01, i, j, 1);
for (int k = 0; k < 4; k++) {
int ni = i + dx[k][0];
int nj = j + dx[k][1];
if (ni <= 0 || nj <= 0 || ni > n || nj > m)
continue;
int id10, id11;
getIDbyINF(id10, ni, nj, 0);
getIDbyINF(id11, ni, nj, 1);
if (xx[ni][nj] == xx[i][j] + 1) {
addedge(id01, id11);
addedge(id10, id00);
}
else if (xx[ni][nj] == xx[i][j]) {
addedge(id00, id11);
addedge(id10, id01);
addedge(id01, id10);
addedge(id11, id00);
}
}
}
for(int i = 1;i <= n;i++)
for (int j = 1; j <= m; j++) {
int id00;
int id01;
getIDbyINF(id00, i, j, 0);
getIDbyINF(id01, i, j, 1);
if (!dfn[id00])
dfs(id00);
if (!dfn[id01])
dfs(id01);
}
/*for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
int id00;
int id01;
getIDbyINF(id00, i, j, 0);
getIDbyINF(id01, i, j, 1);
printf("i=%d j=%d: sc:%d %d\n", i, j, scc[id00], scc[id01]);
}
}*/
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
int x = xx[i][j];
int id00;
int id01;
getIDbyINF(id00, i, j, 0);
getIDbyINF(id01, i, j, 1);
if (scc[id00] > scc[id01])
x++;
printf("%d%c", x, j == m ? '\n' : ' ');
}
}
}
}
inline void getIDbyINF(int & id, int x, int y, bool cc)
{
id = x * m + y;
if (cc) id += n * m;
}
void addedge(int id1, int id2)
{
vec[id1].push_back(id2);
}