*题解:Gym104197D Distance Parities

题目链接

解析

对于 \(a_{i,j} = 0\)\(i,j\) 之间必定没有连边。由于图是联通的,于是存在 \(k\) 使得 \(a_{i,k} = a_{k,j} = 1\)\(a_{i,j} = 0\) 的充要条件,而让 \(a_{i,k}=1\) 的最简单的办法就是令 \(d_{i,j} = 1\),即建一条连接 \(i,k\) 的边。按照这种方式连边,显然能满足所有 \(a_{i,j} = 1\) 的位置。要判断能否满足 \(a_{i,j} = 0\) 的位置,只需把边连上之后跑 Floyd 求最短路再进行判断即可。

时间复杂度 \(O(n ^ 3)\)

实际上这个过程可以用 bitset 优化,利用前面所说的充要条件,将 \(a_i\)\(a_j\) 看成两个 bitset,要判断的就是 \(a_i \operatorname{and} a_j\) 中是否存在 \(1\)

时间复杂度 \(O(\frac{n ^ 3}{w})\)

代码

/*
*/
#include <bits/stdc++.h>
#define eps 0.0000000001
using namespace std;
typedef long long ll;
typedef unsigned ui;
typedef pair<ll, ll> pii;
const int N = 2000 + 5, M = 20, P = 450, mod = 1e9 + 7, mod2 = 1e9 + 7, b1 = 131;
int a[N][N];
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
//	freopen("in.txt","r",stdin);
//	freopen("out1.txt","w",stdout);
	int T;
	cin>>T;
	while(T--){
		int n;
		cin>>n;
		vector<pii> v;
		bitset<2005> d[n + 5];
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				char ch;	
				cin>>ch;
				a[i][j] = ch - '0';
				d[i][j] = a[i][j];
				if(a[i][j] == 1 && j > i){
					v.push_back({i,j});
				}
			}
		}
		bool flag = true;
		for(int i=1;i<=n;i++){
			for(int j=i + 1;j<=n;j++){
				flag &= (d[i] & d[j]).any() || d[i][j];
			}
		}
		if(flag){
			cout<<"YES\n";
			cout<<v.size()<<'\n';
			for(int i=0;i<v.size();i++){
				cout<<v[i].first<<" "<<v[i].second<<'\n';
			}
		}else{
			cout<<"NO\n";
		}
	}
    return 0;
}

posted @ 2026-07-28 21:07  yutar  阅读(1)  评论(0)    收藏  举报