1. 程式人生 > 實用技巧 >CodeForces - 402E Strictly Positive Matrix(tarjan求連通分量個數)

CodeForces - 402E Strictly Positive Matrix(tarjan求連通分量個數)

題目大意:

給出一個矩陣a,滿足\(a_{ij} \geq 0\)\(\sum_{i=1}^n a_{ii} > 0\),問是否存在k使得\(a^k\)為一個嚴格正矩陣。

若b為嚴格正矩陣則滿足任意的\(b_{ij} > 0\)

思路:

題目滿足a中元素都是非負的,結合矩陣乘法的性質可以發現,我們並不關心a矩陣中具體的數值,只關心它是否為0,考慮將a矩陣轉換為一個01矩陣。由01矩陣聯想到鄰接矩陣,對於某一個鄰接矩陣D,如果 \(d_{i,j}=1\) 則表示i,j間有一條邊,那麼嚴格正矩陣的含義就是任意的兩點都存在一條邊,就可以使用tarjan來求連通分量個數進行判斷。

Code:
#include <bits/stdc++.h>
using namespace std;
const int N = 2010;
const int INF = 0x3f3f3f3f;

struct Node {
	int to, next;
} e[N * N * 2];
int head[N], tot;
int dfn[N], low[N], num;
int col;
bool isIns[N];
int st[N], top;

int n;
bool mp[N][N], hasZero;

void add_edge(int u, int v) {
	e[++tot].to = v;
	e[tot].next = head[u];
	head[u] = tot;
}

void tarjan(int u) {
	dfn[u] = low[u] = ++num;
	isIns[u] = 1;
	st[++top] = u;
	for (int i = head[u]; ~i; i = e[i].next) {
		int v = e[i].to;
		if (!dfn[v]) {
			tarjan(v);
			low[u] = min(low[u], low[v]);
		}
		else if (isIns[v]) {
			low[u] = min(low[u], dfn[v]);
		}
	}
	if (low[u] == dfn[u]) {
		++col;
		while (st[top] != u) {
			isIns[st[top--]] = 0;
		}
		isIns[st[top--]] = 0;
	}
}

int main() {
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	memset(head, -1, sizeof(head));
	cin >> n;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			int t; cin >> t;
			if (t)
				mp[i][j] = 1;
			else
				hasZero = 1;
		}
	}
	if (!hasZero) {
		cout << "YES" << endl;
		return 0;
	}
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
			if (mp[i][j])
				add_edge(i, j);
	for (int i = 1; i <= n; i++)
		if (!dfn[i])
			tarjan(i);
	if (col == 1)
		cout << "YES" << endl;
	else
		cout << "NO" << endl;
	return 0;
}