原题传送门
怎么说呢,输入就需要
O
(
n
2
)
O(n^2)
O(n2)的题目有点那个了。。
祭出一个基础算法——并查集!!!
仿照缩点(强连通分量)的想法,如果一个点的集合,对于集合中的每一个点都能找到另一个集合中的点可以与之交换
那么这个点的集合可看成一个点,用并查集维护一下连通性
对于每一个位置,找当下
(
v
i
s
=
0
)
(vis=0)
(vis=0)最小的并且与这个位置联通的点输出
Code:
#include <bits/stdc++.h>
#define maxn 310
using namespace std;
struct data{
int x, id;
}a[maxn];
int f[maxn], vis[maxn], n;
inline int read(){
int s = 0, w = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
return s * w;
}
bool cmp(data x, data y){ return x.x < y.x; }
int getf(int k){ return k == f[k] ? k : f[k] = getf(f[k]); }
int get(){
char c = getchar();
for (; c != '0' && c != '1'; c = getchar());
return c == '1';
}
void Union(int i, int j){
int x = getf(i), y = getf(j);
if (x != y) f[x] = y;
}
int main(){
n = read();
for (int i = 1; i <= n; ++i) a[i] = (data){read(), i}, f[i] = i;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j)
if (get()) Union(i, j);
sort(a + 1, a + 1 + n, cmp);
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j)
if (!vis[a[j].id] && getf(i) == getf(a[j].id)){
vis[a[j].id] = 1, printf("%d ", a[j].x); break;
}
return 0;
}