Codeforces 691D. Swaps in Permutation

题目链接:http://codeforces.com/problemset/problem/691/D

题意:

  给你一个含有 N 个不重复数的序列, 以及 M 对形如 (ai, bj) 的数, (ai ,bj) 代表着可以把第 ai 个数可以和第 bj 个数进行交换, 问如何交换才能使得变换后的字典序最大,每个变化可选可不选,也可选多次.

思路:

  可以想到, 如果 a 可以和 b 换, b 可以和 c 换, 那么 a 就可以间接的和 c 换, 依次类推, 如果某些位置直接可以变换, 那么与这些位置有关系的位置,也可以互相交换. 那么可以把这 N 个点所处的 N 个位置看成一张图上的点, 如果两个位置上的数可以交换, 那么说明图中代表这两个位置的点之间存在一条边,那么这些点和边将会形成若干个连通分支,一个连通分支里的所有点都可以互相交换. 假设某一个连通分支包含着 k 个位置, 既可以说明这 k 个位置上的数可以任意互相交换(直接或者间接),那么由于这 k 个位置上同时又有 k 个数, 这时只需要把这 k 个数按照从大到小的顺序分别填到 k 个位置上, 且这 k 个位置是从前到后的,即从小到大的.所以利用DFS遍历每个连通分支, 记录位置的同时记录位置上的数, 然后把所有这些数从大到小的填到 从小到大的位置上, 这样满足一个位置恰好一个数, 遍历所有连通分支一次, 每个位置上最终的数就确定了.

代码:

 1 #include <bits/stdc++.h>
 2
 3 using namespace std;
 4 typedef long long LL;
 5
 6 const int MAXN = 1000000;
 7 int pt[MAXN + 3]; //存储每个数
 8 int visit[MAXN + 3]; //DFS时的标记数组
 9 int n, m;
10 int ind[MAXN + 3]; //位置
11 int value[MAXN + 3];//值
12 int len;//长度
13
14 int head[MAXN + 3];//链式前向星存图
15 struct NODE {int to; int next; };
16 NODE edge[MAXN * 2 + 3];
17
18 void DFS(int u) { //从位置 u 开始搜索
19     for(int k = head[u]; k != -1; k = edge[k].next){//访问每个与位置 u 相邻的位置
20         if(!visit[edge[k].to]){ //未访问过这个位置
21             visit[edge[k].to] = 1;
22             ind[len] = edge[k].to, value[len++] = pt[edge[k].to - 1];//记录与当前位置相通的位置 以及 每个位置上的数
23             DFS(edge[k].to);
24         }
25     }
26 }
27
28 int cmp(int a, int b) { return a > b; }
29
30 int main() {
31     ios_base::sync_with_stdio(0); cin.tie(0);
32     //freopen("output", "w", stdout);
33     cin >> n >> m;
34     memset(pt, 0, sizeof(pt));
35     for(int i = 0; i < n; i++) cin >> pt[i];
36     memset(head, -1, sizeof(head));
37     for(int i = 1; i <= m; i++) { //以位置为点建图,如果两个位置上的数可以交换那么就说明这两个位置之间存在一条边.
38         int u, v;
39         cin >> u >> v;
40         edge[2 * i - 1].to = v; //链式前向星存图,每条边存两次
41         edge[2 * i - 1].next = head[u];
42         head[u] = 2 * i - 1;
43         edge[2 * i].to = u;
44         edge[2 * i].next = head[v];
45         head[v] = 2 * i;
46     }
47     memset(visit, 0, sizeof(visit));
48     int ans[MAXN + 3] = {0};//保存答案
49     for(int i = 1; i <= n; i++) {//从第一个位置开始搜索与其相通的其他位置
50         if(!visit[i]) {
51             visit[i] = 1;
52             len = 0;//与当前位置相通的位置的个数
53             ind[len] = i;
54             value[len++] = pt[i - 1];
55             DFS(i);
56             sort(ind, ind + len);//对访问到的位置从小到达排序
57             sort(value, value + len, cmp);//对访问到的值从大到下排序
58             for(int j = 0; j < len; j++) ans[ ind[j] ] = value[j];//把较大的值填入到位置较小的位置,每个数恰好只填一次,每个位置也仅有一个数可填
59         }
60     }
61     for(int i = 1; i <= n; i++) cout << (i == 1 ? "":" ") << ans[i];
62     cout << endl;
63     return 0;
64 }
时间: 2024-12-14 18:47:46

Codeforces 691D. Swaps in Permutation的相关文章

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

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

codeforces 691D Swaps in Permutation(并查集)

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

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

Codeforces 134C Swaps

There are n players sitting at a round table. All of them have s cards of n colors in total. Besides, initially the first person had cards of only the first color, the second one had cards of only the second color and so on. They can swap the cards b

codeforces 500B.New Year Permutation 解题报告

题目链接:http://codeforces.com/problemset/problem/500/B 题目意思:给出一个含有 n 个数的排列:p1, p2, ..., pn-1, pn.紧接着是一个 n * n 的矩阵A,当且仅当 Aij = 1 时,pi 与 pj 可以交换数值.现在问如何交换数值,使得最后得到的排列字典序最小. 比赛的时候不会做,看了Tutorial 1 的解法,觉得别人做得太巧妙了,出题者也出得很好 ^_^ 可以看这个:http://codeforces.com/blog

Swaps in Permutation

You are given a permutation of the numbers 1, 2, ..., n and m pairs of positions (aj, bj). At each step you can choose a pair from the given positions and swap the numbers in that positions. What is the lexicographically maximal permutation one can g

[Codeforces 864D]Make a Permutation!

Description Ivan has an array consisting of n elements. Each of the elements is an integer from 1 to n. Recently Ivan learned about permutations and their lexicographical order. Now he wants to change (replace) minimum number of elements in his array

codeforces 622. Optimal Number Permutation 构造

题目链接 假设始终可以找到一种状态使得值为0, 那么两个1之间需要隔n-2个数, 两个2之间需要隔n-3个数, 两个3之间隔n-4个数. 我们发现两个三可以放到两个1之间, 同理两个5放到两个3之间....这样就构造好了. #include <iostream> #include <vector> #include <cstdio> #include <cstring> #include <algorithm> #include <cmat

CodeForces 618B Guess the Permutation

只要找出当前没用过的数字中,大于或等于当前这一列的最大值就可以 #include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<algorithm> using namespace std; const int maxn=100; int n; int x[maxn][maxn]; int ans[maxn]; int flag[maxn]; int mai