1. 程式人生 > >New Year Permutation(並查集+動態容器)

New Year Permutation(並查集+動態容器)

B. New Year Permutation  time limit per test2 seconds  memory limit per test256 megabytes  inputstandard input  outputstandard output  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) 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 

5 2 4 3 6 7 1 
0001001 
0000000 
0000010 
1000001 
0000000 
0010000 
1001000 
output 
1 2 4 3 6 7 5 
input 

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;
}