要求用递归调用做C++的函数。

2025-04-26 19:08:19
推荐回答(1个)
回答1:

#include
#include

using namespace std;

// 类CMatch对应一场比赛
class CMatch
{
private:
int m_A; // 两选手的编号,
int m_B; // 从0开始
bool m_Arranged; // 标记,标志该场比赛是否已安排到某一天

public:
CMatch(int a, int b)
{
m_A = a;
m_B = b;
m_Arranged = false;
}

CMatch()
{
m_A = -1;
m_B = -1;
m_Arranged = false;
}

~CMatch()
{

}

void Print()
{
cout << m_A << " - " << m_B << endl;
}

int GetA()
{
return m_A;
}

int GetB()
{
return m_B;
}

void SetArranged(bool arrange)
{
m_Arranged = arrange;
}

bool IsArranged()
{
return m_Arranged;
}

// 判断p号选手是否参加该场比赛
bool HasPlayer(int p)
{
if (m_A == p || m_B == p)
{
return true;
}

return false;
}

// 判断两场比赛是否是一样的,将a-b和b-a当作一场比赛
bool IsTheSame(CMatch *m)
{
if (HasPlayer(m->GetA()) && HasPlayer(m->GetB()))
{
return true;
}

return false;
}
};

// 类CDay对应比赛日
class CDay
{
private:
int m_size; // 比赛场数
vector m_matches; // 比赛

public:
CDay()
{
m_size = 0;
}

CDay(int size)
{
m_size = size;
}

~CDay()
{

}

// 判断选手a和b是否出现在当天的比赛中,只要a、b之一出现则返回true
bool PlayerExist(int a, int b)
{
for (int i = 0; i < m_matches.size(); i++)
{
if (m_matches[i]->HasPlayer(a) || m_matches[i]->HasPlayer(b))
{
return true;
}
}

return false;
}

// 将一场比赛安排到该天。若能,则安排并返回true,否则返回false
bool Arrange(CMatch *pm)
{
if (m_matches.size() == m_size || PlayerExist(pm->GetA(), pm->GetB()))
{
return false;
}

m_matches.push_back(pm); // 将一场比赛加入当天的安排
pm->SetArranged(true); // 将该场比赛的安排标记设为true,表示已经安排

return true;
}

// 将一场比赛从当天的安排中删除,删除成功返回true,其他返回false
bool Delete(CMatch *pm)
{
if (0 == m_matches.size()) // 当天无安排
{
return false;
}

for (int i = 0; i < m_matches.size(); i++)
{
if (m_matches[i] == pm)
{
pm->SetArranged(false); // 设置比赛为未安排状态
m_matches.erase(m_matches.begin() + i); // 从当天安排中删除该场比赛

break;
}
}

return true;
}

void Print()
{
for (int i = 0; i < m_matches.size(); i++)
{
m_matches[i]->Print();
}
}
};

// 类UtlMatches为工具类
class UtlMatches
{
public:
// 判断pm是否在安排matches中
static bool MatchInMatches(vector &matches, CMatch *pm)
{
bool in_matches = false;

for (int k = 0; k < matches.size(); k++)
{
CMatch *tp = matches[k];

if (tp->IsTheSame(pm))
{
in_matches = true;
break;
}
}

return in_matches;
}

// 结定参赛选手数目n,产生所有的无重复的比赛组合,如a-b与b-a视为重复
static vector GetMatches(int n)
{
vector matches;

for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
if (j != i)
{
CMatch *pm = new CMatch(i, j);

if (MatchInMatches(matches, pm))
{
delete pm;
}
else
{
matches.push_back(pm);
}
}
}
}

return matches;
}

// 从matches里找出第一场未被安排的比赛,无则返回NULL
static CMatch* FindMatch(vector &matches)
{
CMatch *pm = NULL;

for (int i = 0; i < matches.size(); i++)
{
pm = matches[i];

if (!(pm->IsArranged()))
{
return pm;
}
}

return NULL;
}
};

int main(int argc, char *argv[])
{
int n; // 参赛选手数

cout << "Input n:";
cin >> n;

int n_matches = n*(n - 1)/2; // 总比赛场数
int n_matches_day; // 每天比赛场数
int n_days; // 比赛天数

if (n%2 == 0)
{
n_days = n - 1;
}
else
{
n_days = n;
}

n_matches_day = n_matches/n_days;

vector matches = UtlMatches::GetMatches(n); // 生成所有比赛组合存于matches
vector days;

for (int i = 0; i < n_days; i++)
{
days.push_back(new CDay(n_matches_day));
}

CMatch *pm; // 临时指针
CMatch *p_ms[n_matches]; // 指针数组,用于保存已经安排了的match
int a[n_matches]; // 数组a保存每场比赛被安排到了哪一天,元素的值为0到n_days-1
int k = 0; // k为步数,用于回溯控制。这里将每安排一场比赛看作一步

for (int i = 0; i < n_matches; i++) // 初始化a,为接下来的回溯做准备
{
a[i] = -1;
}

// 从matches中找未安排的比赛并安排之,直接所有比赛都被安排
while(NULL != (pm = UtlMatches::FindMatch(matches)))
{
bool arranged = false;
// 将pm安排在第a[k]天后的某一天
for (int i = a[k] + 1; i < n_days; i++)
{
if (days[i]->Arrange(pm)) // 若安排成功
{
p_ms[k] = pm; // 第k步安排了比赛pm
a[k] = i; // 记录比赛pm安排到第i天
k++; // 进入到下一步,即安排下一场比赛
arranged = true; // pm已经安排

break;
}
}

// 要有这样的思想:第k步安排失败是由第k-1步比赛安排安错天了,要退回去将第k-1步安排的比赛安排到另一天
// 再接着安排其他未安排的比赛
if (!arranged) // 若第k步安排比赛失败,则要退回到第k-1步,试着将k-1步的比赛按排到另一天
{
a[k] = -1; // 第k步安排失败,安排到了-1天
k--;
days[a[k]]->Delete(p_ms[k]); // 将第k-1步的比赛安排从第a[k]天删除
}
}

for (int i = 0; i < n_days; i++)
{
cout << "Day:" << i << endl;
(days[i])->Print();
cout << endl;
}

return 0;
}
这里用了回溯法,用递归也差不多。回溯就是递归过程的展开吧,递归隐藏了实现细节。
递归方法:
bool Arrangements(vector &matches, vector &days)
{
CMatch *pm = UtlMatches::FindMatch(matches);

if (NULL == pm) // 当所有比赛都安排完后,自然pm是空,这时候安排终止
{
return true;
}

for (int i = 0; i < days.size(); i++)
{
if (days[i]->Arrange(pm)) // 若安排成功
{
if (Arrangements(matches, days)) // 接着安排下一场比赛,若返回true
{
return true; // 分配终止
}

days[i]->Delete(pm); // 否则分配出错,即该场比赛的天分配错了。
// 先将它从当天的安排中删除,进入for循环试着将它安排到另一天
}
}

return false; // 分配出错
}