Poj 1147 Binary codes bwt压缩算法(很巧妙的一种算法)

题目连接:http://poj.org/problem?id=1147

题目描述:就是求解bwt压缩算法的逆过程。

一个长度为N的01序列,会有N个不同的轮换(当然,字符相同,其中也可能会有相同的),将这N个不同轮换按字典序排序,取排序后的每个轮换的最后一排,组成一个序列。题中给出压缩后的序列,求原始序列,输出的是字典序最小的那个序列

解法:整个解法还挺巧妙的,具体百度上也有解释,简单的根据体重给出的例子说一下:

0 0 0 1 1
0 0 1 1 0
0 1 1 0 0
1 0 0 0 1
1 1 0 0 0

给出的序列中0和1的个数肯定是和原始序列一样的,即由最后一列的数据10010可知原始序列中有2个0和3个1,所以将最后一列(10010)进行排序,即可得到第一列的数据(00011)。上述5*5数组中,将最后一列的数据移到第一列,得一下序列

 

1

0

0

0

1

0

0

0

1

1

0

0

1

1

0

1

1

0

0

0

0

1

1

0

0

(2)

而上述五个轮换中的第一列与第二列是可以知道的,如果要将上述五个轮换按字典序排序后变成(1),则需要进行相应转换,可知如果开头都是1或者都是0则先后顺序仍然不变,只需把①②③④⑤变成②③⑤①④即可,这个时候将(2)中的第二列(00011)与第一列(10010)同时变化,即可得到(1)中的第二列(00101),以此类推,现在(1)中的第一、二列都已经知道,按照同样的推演方式即可得到(1)中,即原始序列中的所有列的元素,即可得到原始序列。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<algorithm>
 6 #define N 3010
 7 using namespace std;
 8 bool last[N], first[N], goal[N], temp[N];
 9 int t[N];
10 int main(){
11     int n, i, j, k, l;
12     while(~scanf("%d",&n)){
13         k=0;
14         for(i=0;i<n;i++){
15             scanf("%d",&last[i]);
16             if(last[i]==0){
17                 first[k]=last[i];
18                 t[i] = k;
19                 k++;
20             }
21         }
22         for(i=0;i<n;i++){
23             if(last[i]==1){
24                 first[k]=last[i];
25                 t[i]=k;
26                 k++;
27             }
28         }
29         goal[0]=first[0];
30         for(j=1;j<n;j++){
31             if(j%2){
32                 for(i=0;i<n;i++){
33                     temp[t[i]]=first[i];
34                 }
35                 goal[j] = temp[0];
36             }
37             else{
38                 for(i=0;i<n;i++){
39                     first[t[i]]=temp[i];
40                 }
41                 goal[j] = first[0];
42             }
43         }
44         for(i=0;i<n-1;i++){
45             printf("%d ",goal[i]);
46         }
47         printf("%d\n",goal[i]);
48     }
49     return 0;
50 }
原文地址:https://www.cnblogs.com/celia01/p/2435548.html