欢迎关注更多精彩
关注我,学习常用算法与数据结构,一题多解,降维打击。
题目大意
https://codeforces.com/contest/1475/problem/F
给定一个初始矩阵和一个目标矩阵,每次操作是可以选择一行或一列进行异或操作。是否可以将初始矩阵转化到目标矩阵。
分析&思路
对于某一行或某一列的异或操作最多不超过1次(操作2次就会还原),所以可以设置行或列的操作次数要么取0,要么取1,直接想到思路就是用2sat表示。
分析一下2sat建立边的过程。
设置初始矩阵为A, 目标矩阵为B。
遍历每一个单元格i,j
如果A[i][j] = A[i][j] 则第i行和第j列要同时变或同时不变。
否则 第i行和第j列有且只有一个变。
AC代码
#include <iostream>
#include <stdio.h>
#include <queue>
#include <string.h>
#include <stack>
#include <vector>
#include <map>
#include <algorithm>
#include <assert.h>
using namespace std;
const int N = 2e5 +10;
const int E = 4e6+10;
// 边属性
class Edge {
public:
int toVertex;
int nextEdge;
};
// 点属性
class Node {
public:
int head;
int indu;
};
class Graph {
public:
Edge edges[E];
Node nodes[N];
int usedEdge=0;
Graph() {
usedEdge = 0;
}
void initEdge(int n) {
for(int i=0;i<=n;++i) {
nodes[i].head=-1;
nodes[i].indu = 0;
}
usedEdge = 0;
}
void addEdge(int a, int b) {
if(a==b) return;
edges[usedEdge].nextEdge = nodes[a].head;
nodes[a].head = usedEdge;
edges[usedEdge].toVertex = b;
nodes[b].indu++;
usedEdge++;
// cout<<"add edge: "<<a<<","<<b<<endl;
}
int dfn[N], low[N];
stack<int> st;
int deep, sum;
int color[N];
void initTarjan(int n) {
deep = 0;
sum=0;
memset(dfn, 0,sizeof(int)*n);
memset(low, 0,sizeof(int)*n);
memset(color, 0,sizeof(int)*n);
}
void tarjan(int u) {
dfn[u] = ++deep;
low[u] = deep;
st.push(u);
for(int i=nodes[u].head;i>=0;i = edges[i].nextEdge) {
int v = edges[i].toVertex;
if(!dfn[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
} else if(!color[v]) {
low[u] = min(low[u], dfn[v]);
}
}
if(dfn[u]==low[u]) {
color[u] = ++sum;
while(st.top()!=u) {
int v = st.top();
st.pop();
color[v]=sum;
}
st.pop();
}
}
map<int, int> loc;
bool topo(int n, bool deb) {
queue<int>qu;
for(int i=1;i<=n;++i) {
if(nodes[i].indu==0) {
qu.push(i);
}
}
int l=0;
while(!qu.empty()) {
int f = qu.front();
loc[f]=++l;
qu.pop();
for(int i=nodes[f].head;i>=0;i=edges[i].nextEdge) {
int v = edges[i].toVertex;
nodes[v].indu--;
if(nodes[v].indu==0){
qu.push(v);
}
}
}
if(deb) cout<<l<<endl;
return l==n;
}
};
Graph og;
// false not swap
void either(int i, bool si, int j, bool sj) {
og.addEdge(i*2+(si^1), 2*j+sj);
og.addEdge(j*2+(sj^1), 2*i+si);
}
void imply(int i, bool si, int j, bool sj) {
either(i, si^1, j, sj);
}
void must(int i, bool sel) {
og.addEdge(i*2+(sel^1), i*2+sel);
}
char C[1010][1010];
char C2[1010][1010];
void solve() {
int n;
scanf("%d", &n);
for(int i=0;i<n;++i) {
scanf("%s", C+i);
}
for(int i=0;i<n;++i) {
scanf("%s", C2+i);
}
og.initEdge(4*n);
for(int i=0;i<n;++i)for(int j=0;j<n;++j) {
if(C[i][j] == C2[i][j]) {
// 同时变或同时不变
imply(i, 1, j+n , 1);
imply(i, 0, j+n , 0);
} else {
imply(i, 0, j+n, 1);
imply(i, 1, j+n, 0);
}
}
int c = 2*n;
og.initTarjan(2*c);
for(int i=0;i<2*c;++i) {
if(!og.dfn[i])og.tarjan(i);
}
vector<int> ans;
for(int i=0;i<c;++i) {
if(og.color[2*i]==og.color[2*i+1]){
puts("NO");
return;
}
}
puts("YES");
}
int main() {
int t;
scanf("%d", &t);
while(t--)
solve();
return 0;
}
/*
*/
本人码农,希望通过自己的分享,让大家更容易学懂计算机知识。