codeforces1438C Engineer Artem (#682 Div2)

本文解析了CodeForces上的一道题目,该题要求通过调整矩阵中的元素来避免相邻元素相同。文章详细介绍了如何利用2-SAT算法解决此问题,并提供了完整的C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:

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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值