输入一个由男女程序员组成的序列FFMMFMMMFF,现要通过适当的交换操作让女程序员全部排在男程序员前面,即使原序列变成FFFFFMMMMM,问至少需要交换多少次,交换次数最少的交换操作是什么?
以下程序效率不高,但使用该程序在每次都将被交换的女程序员放在已得到的从序列头开始连续排列的女程序员序列的最后一个女程序员的后一位置的情况下可找出所有可能的交换操作序列,所以还是有一定的价值.
至于最小交换次数,假设女程序员有F个,我们只需得到序列从头部算起连续F个程序员中男程序员的数目,即为最小交换次数,至于为什么以及交换次数最小的操作序列是什么留做习题,因为很容易想到
代码如下:
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#define MALE 5 //队列中男程序员位数
#define FEMALE 5 //队列中女程序员位数
using namespace std;
struct swap //记录交换操作的结构体类型
{
int k; //右交换下标
int i; //左交换下标
swap(int k, int i) :k(k), i(i) {}
};
string::size_type number(string::size_type i, const string& que); //函数,寻找当前序列索引下标i后的第一位女程序员下标,找到返回下标,没有找到返回-1
int main()
{
string::size_type start; //从队列开头起连续排列的女程序员序列中最后一位女程序员下标,若队列第一位是男程序员,start为-1
string que = "0010011111"; //存放男女程序员队列的数组,字符'0'代表男程序员,'1'代表女程序员
/*cout << "输入男女程序员序列,0男1女" << endl; //输入男女程序员序列
cin >> que;*/
start = 0;
while (que[start] != '0') //确定从队列开头起连续排列的女程序员序列中最后一位女程序员下标
start++;
if (start == FEMALE) //女程序员已全部放到男程序员前面,无需交换
{
std::cout << "最小交换次数为0" << endl;
}
else
{
string::size_type i = start, k, count = 0, minswap; //i为回溯过程中前进深度,任何时候下标i及i前面下标位置的元素均为女程序员,k为在某下标之后找到的第一位女程序员标号/count用于统计交换次数,minswap为最小交换次数
bool TF = false, flag = false; //TF为true表示从上一轮回溯至本轮,为false表示从上一轮前进至本轮
vector<::swap> run;
vector<::swap> result;
while (true)
{
if (TF == false) //进至新的一层,从i后开始寻找第一个女程序员位置
{
k = number(i, que);
}
else
{
k = number(k + 1, que); //回溯至本层,从上一次找到的女程序员位置后寻找第一个女程序员
if (i == start)
{
if (k == que.size()) //在start处已无法找到下一个可交换女程序员,试探结束
break;
}
}
string::size_type count1 = count;
if (i != start)
{
if (k == que.size())
{
if (TF == false)
{
if (flag == false || minswap > count) //所有女程序员均已排到男程序员前面,判断flag值,比较count以决定是否更新
{
result = run;
minswap = count;
flag = true;
}
}
k = run.back().k; //找到最后一轮交换操作(i,k)
i = run.back().i;
count--;
run.pop_back();
//i--; //回溯至上一层
TF = true;
}
}
if (count1 == count)
TF = false;
if (TF || i == start || k != i) //进入本层时TF==false,此时从i后寻找第一个女程序员下标,由于找到的女程序员要和i位置交换,所以,若该女程序员就位于i位置,该段语句不执行,否则就应将找到的女程序员k和i交换,并将交换操作放入run表
std::swap(que[i], que[k]); //找到可交换女程序员k,交换i,,和k
if (TF == false && (i == start || k != i))
{
count++;
run.push_back(::swap(k, i)); //交换操作(i, k)加入链表
}
if (TF == false)
i++; //递进至下一层
}
std::cout << "把女程序员交换至最前面所需最小交换次数为" << minswap << endl; //输出最小交换次数
std::cout << "交换次数最小的交换方式为:" << endl;
i = start + 1;
for (const ::swap& go : result) //输出交换操作
{
std::cout << "交换序列中第" << go.i + 1 << "个和第" << go.k + 1 << "个程序员" << endl;
}
}
return 0;
}
string::size_type number(string::size_type i, const string& que)
{
for (string::size_type j = i; j < que.size(); j++)
{
if (que[j] == '1')
return j;
}
return que.size();
}