题目大意:计算全排列中某一序列,与给定序列的逆序差之和最小。
解题思路:
1.在计算逆序差之和最小前,首先要算逆序差。
根据题意序列为ABCDE的全排列,我们可定义10个字母对,即:
AB、AC、AD、AE、BC、BD、BE、CD、CE、DE
如果当前序列A在B之前,我们令AB为1,若B在A之前AB为-1。
这样当输入某序列时,可以得到一个10位的key。
计算逆序差即为计算两个序列10位key的汉明距离。
2.利用STL中next_permutation () 可以得到序列的全排列。
再计算每一序列的key与初始各序列的汉明距离之和,即所求逆序差之和。
输出最小和的序列即可。
#include <iostream>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
struct Record{
int mark[10];
};
int comp(int* a,int* b){
int result = 0;
for( int i = 0; i < 10; i++ ){
if( a[i] != b[i] )
result++;
}
return result;
}
int main(){
int m;
char result[6];
char ranks[101][5];
char letter[] = {'A','B','C','D','E'};
char pairs[10][2] = {{'A','B'},{'A','C'},{'A','D'},{'A','E'},{'B','C'},
{'B','D'},{'B','E'},{'C','D'},{'C','E'},{'D','E'}};
vector<Record> v;
while( cin >> m && m ){
int min = 999999;
for( int i = 0; i < m; i++ ){
Record r;
memset(r.mark,0,sizeof(r.mark));
for( int j = 0; j < 5; j++){
cin >> ranks[i][j];
// 扫描数字对进行赋值
for( int k = 0; k < 10; k ++ ){
if( pairs[k][1] == ranks[i][j] && !r.mark[k] ) r.mark[k] = -1;
if( pairs[k][0] == ranks[i][j] && !r.mark[k] ) r.mark[k] = 1;
}
}
v.push_back(r);
}
do {
int tmp = 0;
int mark[10] = {0};
// 得到当前组合的mark
for( int s = 0; s < 5; s++ ){
for( int k = 0; k < 10; k ++ ){
if( pairs[k][1] == letter[s] && !mark[k] ) mark[k] = -1;
if( pairs[k][0] == letter[s] && !mark[k] ) mark[k] = 1;
}
}
for( int t = 0; t < m; t++ ){
Record r = v[t];
tmp += comp( r.mark, mark );
}
if( tmp < min ){
min = tmp;
strncpy ( result,letter,5 );
result[5] = '\0';
}
} while ( next_permutation (letter,letter+5) );
cout << result << " is the median ranking with value " << min << "." << endl;
v.clear();
}
return 0;
}