小Q的变换

小Q的变换

时间限制: 1 Sec  内存限制: 128 MB

题目描述

给定一个1到n的某个排列p和一个变换矩阵,现在可以根据这个变换矩阵交换排列中一对或⼏对元素的位置,可以交换无数次,问这样得到的字典序最小的排列是哪一个。
1到n的排列是一个含n个数字的数列,其中1到n各个数字都恰好出现一次。
变换矩阵是一个n*n的01矩阵,其中的元素只有0和1。如果第i行第j列是1,则表示排列中第i个元素和第j个元素这一对能交换位置。如果是0,则不能交换位置。保证该矩阵关于沿左上到右下的对角线对称。
字典序最小是指使得小的数字尽可能的在前面,⼤的数字尽可能在后面。如12345的字典序比12354更小。

输入

第一行输入1个数字n,表示是1到n的排列。
第二行n个数字,依次表示排列p中的数。
第3到n+2行,每行n个字符,形成n*n的变换矩阵。(只可能出现0/1)

输出

输出一行n个数字,表示你的答案。

样例输入

5
4 2 1 5 3
00100
00011
10010
01101
01010

样例输出

1 2 3 4 5

提示

对于30%数据,1≤n≤10
对于60%数据,1≤n≤50
对于100%数据,1≤n≤300

题解

用并查集分为几个联通块,每个联通块内进行排序。

 1 #include<vector>
 2 #include<cstdio>
 3 #include<iostream>
 4 #include<algorithm>
 5 using namespace std;
 6 int n,a[330],f[330],b[330];
 7 char c[330][330];
 8 vector<int>g[330];
 9 int _find(int x)
10 {
11     if(f[x]!=x)
12         f[x]=_find(f[x]);
13     return f[x];
14 }
15 int main()
16 {
17     scanf("%d",&n);
18     for(int i=1;i<=n;i++)
19         f[i]=i;
20     for(int i=1;i<=n;i++)
21         scanf("%d",&a[i]);
22     for(int i=1;i<=n;i++)
23         scanf("%s",c[i]+1);
24     for(int i=1;i<=n;i++)
25         for(int j=i+1;j<=n;j++)
26         {
27             if(c[i][j]!='1')
28                 continue;
29             int fi=_find(i);
30             int fj=_find(j);
31             f[fj]=f[fi];
32         }
33     for(int i=1;i<=n;i++)
34     {
35         int fi=_find(i);
36         g[fi].push_back(a[i]);
37     }
38     for(int i=1;i<=n;i++)
39     {
40         if(f[i]!=i)
41             continue;
42         sort(g[i].begin(),g[i].end());
43         int t=0;
44         for(int j=1;j<=n;j++)
45             if(f[j]==i)
46                 b[j]=g[i][t++];
47     }
48     for(int i=1;i<n;i++)
49         printf("%d ",b[i]);
50     printf("%d\n",b[n]);
51     return 0;
52 }
View Code

 

posted @ 2020-01-16 14:56  Johnny-English  阅读(219)  评论(0)    收藏  举报