Tree Orientation (Easy Version)
Tree Orientation (Easy Version)
偏序关系,哈斯图
利用可达性建树,无法通过中间节点而可达的点建边,最后检查树是否完整
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void solve() {
int n; cin >> n;
vector<string> g(n);
for(int i = 0; i < n; i ++) cin >> g[i];
//自反性
for(int i = 0; i < n; i ++)
if(g[i][i] == '0') {cout << "NO\n"; return;}
//反对称性
for(int i = 0; i < n; i ++) {
for(int j = i + 1; j < n; j ++)
if(i != j && g[i][j] == '1' && g[j][i] == '1') {cout << "NO\n"; return;}
}
//传递性
for(int i = 0; i < n; i ++) {
for(int j = 0; j < n; j ++) {
if(i == j) continue;
if(g[i][j] == '1') {
for(int k = 0; k < n; k ++)
if(g[j][k] == '1' && g[i][k] != '1') {cout << "NO\n"; return;}
}
}
}
vector<pair<int, int>> edge;//找边
for(int i = 0; i < n; i ++) {
for(int j = 0; j < n; j ++) {
if(i == j) continue;
if(g[i][j] == '1') {
bool covered = false;
for(int k = 0; k < n; k ++) {
if(k == i || k == j) continue;
if(g[i][k] == '1' && g[k][j] == '1') {covered = true; break;}
}
if(!covered) edge.push_back({i+1, j+1});
}
}
}
if(edge.size() != n - 1) {cout << "NO\n"; return;}
vector<vector<int>> adj(n + 1);
for(auto [u, v] : edge) {
adj[u].push_back(v);
adj[v].push_back(u);
}
queue<int> q; q.push(1);
vector<int> vis(n + 1, 0); vis[1] = 1;
int cnt = 0;
while(!q.empty()) {
int u = q.front(); q.pop();
cnt ++;
for(int v : adj[u]) {
if(!vis[v]) {
vis[v] = 1;
q.push(v);
}
}
}
if(cnt != n) {cout << "NO\n"; return;}
cout << "YES\n";
for(auto [u, v] : edge) cout << u << " " << v << "\n";
}
int main() {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int _ = 1; cin >> _;
while(_--) solve();
return 0;
}

浙公网安备 33010602011771号