New Year Permutation(並查集+動態容器)
Permutation a1, a2, …, an is prettier than permutation b1, b2, …, bn, if and only if there exists an integer k (1 ≤ k ≤ n) where a1 = 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 ≤ n, Ai, j = Aj, i holds. Also, for all integers i where 1 ≤ i ≤ n, Ai, 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
7
5 2 4 3 6 7 1
0001001
0000000
0000010
1000001
0000000
0010000
1001000
output
1 2 4 3 6 7 5
input
5
4 2 1 5 3
00100
00011
10010
01101
01010
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 個數的排列:p1, p2, ..., pn-1, pn。緊接著是一個 n * n 的矩陣A,當且僅當 Aij = 1 時,pi 與 pj 可以交換數值。現在問如何交換數值,使得最後得到的排列字典序最小。
比賽的時候不會做,看了Tutorial 1 的解法,覺得別人做得太巧妙了,出題者也出得很好 ^_^
可以看這個:http://codeforces.com/blog/entry/15488
它是利用了並查集來做的。如果遇到 Aij = 1 的話,就將點 i 和 點 j 連一條邊。最終會得到一些互不相交的集合。以第一組 test 來說吧~~~
這就表示位置 1、4、7 的數是可以交換的,位置 2、5 要保持原封不動,位置 3、6 的數可以交換。由於每個集合都有一個祖先,即第一層的那個數,依次為 7、2、5、6,然後就把每個集合的數放到以該集合祖先為首的 vector 數組裡面,並把每個集合內的數從小到大排序。最後遍歷位置 1 ~ n,根據每個位置的數所屬的集合(以哪個祖先為首),依次輸出。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
int a[305];
int f[305];
int c[305];
vector<int>vec[305];
int find(int x)
{
int i,j,r;
r=x;
while(f[r]!=r)
r=f[r];
return r;
}
int root(int x,int y)
{
int px=find(x);
int py=find(y);
if(f[px]!=f[py])
f[px]=py;
}
int main()
{
int n;
scanf("%d",&n);
memset(c,0,sizeof(c));
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
f[i]=i;
}
for(int i=1;i<=n;i++)
{
char s[305];
scanf("%s",s+1);
for(int j=i;j<=n;j++)
{
if(s[j]=='1')
{
root(i,j);
}
}
}
for(int i=1;i<=n;i++)
{
int v=find(i);
vec[v].push_back(a[i]);
}
for(int i=1;i<=n;i++)
{
sort(vec[i].begin(),vec[i].end()); //排序
}
for(int i=1;i<n;i++)
printf("%d ",vec[find(i)][c[find(i)]++]); //輸出每個容器的數,輸出的前先令c陣列都為0,這樣下次輸入可按當前順序
printf("%d\n",vec[find(n)][c[find(n)]++]);
return 0;
}