CF 500 B. New Year Permutation 并查集

User ainta has a permutation p1, p2, ..., pn. As the New Year is coming, he wants to make his permutation as pretty as possible.

Permutation a1, a2, ..., an is prettier than permutation b1, b2, ..., bn, if and only if there exists an integer k (1 ≤ k ≤ n) wherea1 = b1, a2 = b2, ..., ak - 1 = bk - 1 and ak < bk all holds.

As known, permutation p is so sensitive that it could be only modified by swapping two distinct elements. But swapping two elements is harder than you think. Given an n × n binary matrix A, user ainta can swap the values of pi and pj (1 ≤ i, j ≤ n,i ≠ j) if and only if Ai, j = 1.

Given the permutation p and the matrix A, user ainta wants to know the prettiest permutation that he can obtain.

Input

The first line contains an integer n (1 ≤ n ≤ 300) — the size of the permutation p.

The second line contains n space-separated integers p1, p2, ..., pn — the permutation p that user ainta has. Each integer between 1 and n occurs exactly once in the given permutation.

Next n lines describe the matrix A. The i-th line contains n characters ‘0‘ or ‘1‘ and describes the i-th row of A. The j-th character of the i-th line Ai, j is the element on the intersection of the i-th row and the j-th column of A. It is guaranteed that, for all integers i, j where 1 ≤ i < j ≤ nAi, j = Aj, i holds. Also, for all integers i where 1 ≤ i ≤ nAi, i = 0 holds.

Output

In the first and only line, print n space-separated integers, describing the prettiest permutation that can be obtained.

Sample test(s)

input

75 2 4 3 6 7 10001001000000000000101000001000000000100001001000

output

1 2 4 3 6 7 5

input

54 2 1 5 30010000011100100110101010

output

1 2 3 4 5

Note

In the first sample, the swap needed to obtain the prettiest permutation is: (p1, p7).

In the second sample, the swaps needed to obtain the prettiest permutation is (p1, p3), (p4, p5), (p3, p4).

A permutation p is a sequence of integers p1, p2, ..., pn, consisting of n distinct positive integers, each of them doesn‘t exceed n. The i-th element of the permutation p is denoted as pi. The size of the permutation p is denoted as n.

题意:

给出一个序列,长度为n

然后是n*n的矩阵,矩阵的值为0或者1

maze[i][j]=1表示序列第i个和序列第j个可以交换

maze[i][j]=0表示序列第i个和序列第j个不可以交换

矩阵保证maze[i][j]=maze[j][i]

现在你可以进行操作:若2个数可以交换,你可以交换他们,也可以不交换

你可以操作无限次

问最后得到的最小序列是多少?

2个序列,若第一个不相等的数越小,该序列越小

并查集,把可以交换的那一堆位置的值放在一起

对于序列第i个位置,找到i属于哪一堆,再从这一堆中还没有用过的数中挑出一个最小的数,放在第i的位置。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4
 5 using namespace std;
 6
 7 const int maxn=350;
 8 const int inf=0x3f3f3f3f;
 9 int ans[maxn][maxn];    //第i堆数的值
10 int iter[maxn];         //现在第i堆数中要拿的数是第iter[i]个,即这一堆中还没有用过的数中的最小值是第iter[i]个
11 int fa[maxn];           //并查集
12 int init[maxn];         //存放初始序列的值
13 int num[maxn];          //第i个位置属于第num[i]堆
14 int print[maxn];        //存放最后的序列,方便输出
15 int len[maxn];          //第i堆数有len[i]个
16 char str[maxn];         //方便输入数据
17
18 int find_fa(int x)
19 {
20     if(fa[x]==x)
21         return x;
22     else
23         return fa[x]=find_fa(fa[x]);
24 }
25
26 int main()
27 {
28     int n;
29     scanf("%d",&n);
30     for(int i=1;i<=n;i++){
31         for(int j=1;j<=n;j++)
32             ans[i][j]=inf;
33     }
34
35     for(int i=1;i<=n;i++)
36         scanf("%d",&init[i]);
37     for(int i=1;i<=n;i++)
38         fa[i]=i;
39     for(int i=1;i<=n;i++){
40         scanf("%s",str);
41         for(int j=1;j<=n;j++){
42             int u=str[j-1]-‘0‘;
43             if(u>0){
44                 int fai=find_fa(i);
45                 int faj=find_fa(j);
46                 if(fai!=faj)
47                     fa[faj]=fai;
48             }
49         }
50     }
51     //printf("eee\n");
52     for(int i=1;i<=n;i++){
53         len[i]=1;
54         num[i]=-1;
55     }
56     int tot=1;
57     for(int i=1;i<=n;i++){
58         int cnt=find_fa(i);
59         if(num[cnt]>0){
60             num[i]=num[cnt];
61             ans[num[i]][len[num[i]]++]=init[i];
62         }
63         else{
64             num[cnt]=tot;
65             num[i]=tot;
66             ans[tot][len[tot]++]=init[i];
67             tot++;
68         }
69     }
70     for(int i=1;i<tot;i++){
71         sort(ans[i]+1,ans[i]+len[i]);
72     }
73     for(int i=1;i<tot;i++)
74         iter[i]=1;
75     for(int i=1;i<=n;i++){
76         print[i]=ans[num[i]][iter[num[i]]++];
77     }
78     for(int i=1;i<n;i++)
79         printf("%d ",print[i]);
80     printf("%d\n",print[n]);
81
82     return 0;
83 }

时间: 2024-10-13 11:00:11

CF 500 B. New Year Permutation 并查集的相关文章

Educational Codeforces Round 14 D. Swaps in Permutation (并查集orDFS)

题目链接:http://codeforces.com/problemset/problem/691/D 给你n个数,各不相同,范围是1到n.然后是m行数a和b,表示下标为a的数和下标为b的数可以交换无数次.问你最后字典序最大的数列是什么. 将下面的a和b用并查集联系起来存到祖节点对应的数组中,然后从大到小排序数组,最后依次按照父节点的数组中的顺序输出. 也可以用dfs的方法解(略麻烦),形成一个环路的就在一个数组中... 1 //并查集 2 #include <bits/stdc++.h> 3

CF.1027F.Session in BSU(思路 并查集)

题目链接 \(Description\) 有\(n\)个人都要参加考试,每个人可以在\(ai\)或\(bi\)天考试,同一天不能有两个人考试.求最晚考试的人的时间最早能是多少.无解输出-1. \(Solution\) 把每个人向\(ai,bi\)连边.对于每个连通块单独考虑. 记点数为n,边数为m.可以发现当某一连通块n>m(n=m+1)时,可以有一个点不选(最大的): 当n=m时,所有点都要选:n<m时,无解. 用并查集维护连通,顺便维护最大.次大值.当第一次出现环时,即n=m:第二次出现就

cf 990G GCD Counting (莫比乌斯反演 并查集)

990G 给你一棵树,问你有多少个点对(x,y)(x\(\leq\)y),使得(x,y)简单路径上的点权值的\(gcd\)为\(i\),对于\(i\in [1,200000]\)输出点对数目. 这题没有做出来,主要还是莫比乌斯反演时间太长不熟悉了.同时统计点对的技巧也自己没有想出来,实在是不应该. 我们设\(h(i)\)是有多少个点对(x,y)(x\(\leq\)y),使得(x,y)简单路径上的点权值的\(gcd\)为\(i\)的倍数的答案.于是有\(h(i)=\sum_{i=1}^{\lflo

B. Mr. Kitayuta&#39;s Colorful Graph (CF #286 (Div. 2) 并查集)

B. Mr. Kitayuta's Colorful Graph time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output Mr. Kitayuta has just bought an undirected graph consisting of n vertices and m edges. The vertices of the g

CF 115 A 【求树最大深度/DFS/并查集】

CF A. Party time limit per test3 seconds memory limit per test256 megabytes inputstandard input outputstandard output A company has n employees numbered from 1 to n. Each employee either has no immediate manager or exactly one immediate manager, who

codeforces 691D Swaps in Permutation(并查集)

题意: 给你一个长度为n的数列,然后给你m组数, 表示这两个数可以交换 然后让你给出字典序最大的数列 思路: 用并查集,可交换的数都是成组的,把同一并查集中的数加在根节点的vector后, 在一个并查集中的数,从大到输出就好了 /* *********************************************** Author :devil ************************************************ */ #include <cstdio>

[CF#250 Div.2 D]The Child and Zoo(并查集)

题目:http://codeforces.com/problemset/problem/437/D 题意:有n个点,m条边的无向图,保证所有点都能互通,n,m<=10^5 每个点都有权值,每条边的权值定义为这条边连接两点的权值中的最小值. f(p,q)表示p到q的路径中边权的最小值,如果有多条路经,就取每条路径最小值中的最小值 要求的就是对于所有1<=p<=n,1<=q<=n,p≠q,f(p,q)的平均值 分析: 刚开始是想考虑每条边对总和的贡献,结果没想通. 一个很巧的办法

【搜索】【并查集】Codeforces 691D Swaps in Permutation

题目链接: http://codeforces.com/problemset/problem/691/D 题目大意: 给一个1到N的排列,M个操作(1<=N,M<=106),每个操作可以交换X Y位置上的数字,求可以得到的最大字典序的数列. 题目思路: [搜索][并查集] 这题可以用搜索或者并查集写,都能过. 把位置分成若干块,每一块里面的位置都是可以被这一块里另一个位置经过若干次调换的(类似强连通,位置可达). 然后把每一块位置里的 位置按从小到大排序,位置上的值按从大到小排序,依次填入位置

CF 371D Vessels 【并查集】

给出一个竖着的n个容器每个容器的容积,从上到下分别是1,2,3,4,,n,从某点开始浇水,保证该层满了后水能流向下一层,一层一层,直到不再溢出或者最底下都装满了留到地上去了为之. 给出n个操作/询问 在x点浇p的水 查询x点的水量 这题平妈想的,用并查集来做. 很容易想到暴力的方法,就是,如果是从m点开始浇水,则,我一个一个来处理m以后的点,如果这点点满了就下一个,一直到找到没满的点,慢慢地放置这些水. 这里有个很需要优化的量,我怎么快速知道从某个点开始距离它最近的有水的点位是什么(因为就算后面