Algorithm 查找路径的算法(调度类)
我正试图找出解决这个问题的方法1.这是为12年级学生举办的一次程序设计比赛的结果。 任务是让学生“Karli”参加足够的课程以获得214学分。学生在进入考场前不得超过或少于214学分。门如图所示。用户可以为其他课程重复一个课程,但他们必须离开该教室..转到另一个教室..然后再回来 我尝试手动执行此操作,并能够找到一个路径为的解决方案: 数学代数哲学代数数学建模微积分建模考试 我正在尝试开发一种算法,该算法将在给定所需学分数的情况下找到一条路径(本例为214) 以下是我尝试过并坚持的内容: 将地图表示为图形,门是两个节点之间的一条双边边。然而,我不知道什么样的图遍历算法将允许我解决这个问题 将图形转换为邻接矩阵会使事情变得更容易吗Algorithm 查找路径的算法(调度类),algorithm,graph,graph-traversal,Algorithm,Graph,Graph Traversal,我正试图找出解决这个问题的方法1.这是为12年级学生举办的一次程序设计比赛的结果。 任务是让学生“Karli”参加足够的课程以获得214学分。学生在进入考场前不得超过或少于214学分。门如图所示。用户可以为其他课程重复一个课程,但他们必须离开该教室..转到另一个教室..然后再回来 我尝试手动执行此操作,并能够找到一个路径为的解决方案: 数学代数哲学代数数学建模微积分建模考试 我正在尝试开发一种算法,该算法将在给定所需学分数的情况下找到一条路径(本例为214) 以下是我尝试过并坚持的内容: 将地图
谢谢
广度优先搜索
将解决此问题
记录Karli到达编号为room
的房间时的状态(房间,信用)
,信用值记录在credit
中
使用队列
维护数据。开始时,队列中只有(外部,0)。每次,弹出头部,从head
描述的状态移动到head
的每个相邻房间,然后计算新的状态并将它们推到队列的末尾(记住使用散列以避免重复添加相同的状态)
当达到状态(考试,214)
时,展开过程完成。剩下的工作是从状态返回(考试,214)
。在BFS中获得新状态时,还可以记录指向前体状态的指针
这是我的密码
char name[][15] = {
"exam",
"stochastic",
"modeling",
"calculus",
"math",
"modern arts",
"algebra",
"philosophy",
"outside"
};
int credits[]={0, 23, 29, 20, 17, 17, 35, 32, 0};
int neighbour[][7]={
{ 1, 2, -1},
{ 2, 3, -1},
{ 0, 1, 3, 4, 5, -1},
{ 1, 2, 4,-1},
{ 2, 3, 6, -1},
{ 2, 6, 7, -1},
{ 4, 5, 7, -1},
{ 5, 6, -1},
{ 4, -1}
};
class Node{
public:
int pos;
int credit;
bool operator <( const Node a) const{
return pos < a.pos || pos == a.pos && credit < a.credit;
}
};
vector<Node> Q;
vector<int> pred;
set<Node> hash;
void bfs(){
int n = 9;
bool found = false;
hash.clear();
Node start;
start.pos = 8, start.credit = 0;
Q.push_back(start);
pred.push_back(-1);
hash.insert(start);
for(int f=0; f<Q.size(); ++f){
Node head = Q[f];
int pos = head.pos;
//printf("%d %d -> \n", head.pos, head.credit);
for(int i=0; neighbour[pos][i]!=-1; ++i){
Node tmp;
tmp.pos = neighbour[pos][i];
tmp.credit = head.credit + credits[tmp.pos];
if(tmp.credit > 214) continue;
if(hash.count(tmp)) continue;
if(tmp.credit !=214 && tmp.pos==0)continue; // if the credit is not 214, then it is not allowed to enter exame room(numbered as 0)
Q.push_back(tmp);
pred.push_back(f);
//printf(" -> %d, %d\n", tmp.pos, tmp.credit);
if(tmp.credit==214 && tmp.pos==0){
found = true;
break;
}
}
if(found)break;
}
stack<int> ss;
int idx = Q.size()-1;
while(true){
ss.push(Q[idx].pos);
if(pred[idx]!=-1) idx=pred[idx];
else break;
}
for(int credit=0; ss.size() > 0; ){
int pos = ss.top();
credit += credits[pos];
printf("%s(%d) ", name[pos], credit);
ss.pop();
}
printf("\n");
}
广度优先搜索
将解决此问题
记录Karli到达编号为room
的房间时的状态(房间,信用)
,信用值记录在credit
中
使用队列
维护数据。开始时,队列中只有(外部,0)。每次,弹出头部,从head
描述的状态移动到head
的每个相邻房间,然后计算新的状态并将它们推到队列的末尾(记住使用散列以避免重复添加相同的状态)
当达到状态(考试,214)
时,展开过程完成。剩下的工作是从状态返回(考试,214)
。在BFS中获得新状态时,还可以记录指向前体状态的指针
这是我的密码
char name[][15] = {
"exam",
"stochastic",
"modeling",
"calculus",
"math",
"modern arts",
"algebra",
"philosophy",
"outside"
};
int credits[]={0, 23, 29, 20, 17, 17, 35, 32, 0};
int neighbour[][7]={
{ 1, 2, -1},
{ 2, 3, -1},
{ 0, 1, 3, 4, 5, -1},
{ 1, 2, 4,-1},
{ 2, 3, 6, -1},
{ 2, 6, 7, -1},
{ 4, 5, 7, -1},
{ 5, 6, -1},
{ 4, -1}
};
class Node{
public:
int pos;
int credit;
bool operator <( const Node a) const{
return pos < a.pos || pos == a.pos && credit < a.credit;
}
};
vector<Node> Q;
vector<int> pred;
set<Node> hash;
void bfs(){
int n = 9;
bool found = false;
hash.clear();
Node start;
start.pos = 8, start.credit = 0;
Q.push_back(start);
pred.push_back(-1);
hash.insert(start);
for(int f=0; f<Q.size(); ++f){
Node head = Q[f];
int pos = head.pos;
//printf("%d %d -> \n", head.pos, head.credit);
for(int i=0; neighbour[pos][i]!=-1; ++i){
Node tmp;
tmp.pos = neighbour[pos][i];
tmp.credit = head.credit + credits[tmp.pos];
if(tmp.credit > 214) continue;
if(hash.count(tmp)) continue;
if(tmp.credit !=214 && tmp.pos==0)continue; // if the credit is not 214, then it is not allowed to enter exame room(numbered as 0)
Q.push_back(tmp);
pred.push_back(f);
//printf(" -> %d, %d\n", tmp.pos, tmp.credit);
if(tmp.credit==214 && tmp.pos==0){
found = true;
break;
}
}
if(found)break;
}
stack<int> ss;
int idx = Q.size()-1;
while(true){
ss.push(Q[idx].pos);
if(pred[idx]!=-1) idx=pred[idx];
else break;
}
for(int credit=0; ss.size() > 0; ){
int pos = ss.top();
credit += credits[pos];
printf("%s(%d) ", name[pos], credit);
ss.pop();
}
printf("\n");
}
以下是Haskell中的一个版本,从检查室向后生成路径,并丢弃信用总额大于要求的路径:
import Data.Maybe (fromJust)
import Control.Monad (guard)
classes = [("exam",["modeling"])
,("modeling",["exam","stochastic","calculus","math","modern arts"])
,("stochastic",["calculus","modeling"])
,("calculus",["stochastic","modeling","math"])
,("math",["calculus","modeling","algebra"])
,("algebra",["math","philosophy"])
,("philosophy",["algebra","modern arts"])
,("modern arts",["philosophy","modeling"])]
credits = [("exam",0)
,("modeling",29)
,("stochastic",23)
,("calculus",20)
,("math",17)
,("algebra",35)
,("philosophy",32)
,("modern arts",17)]
solve requirement = solve' ["exam"] 0 where
solve' path creditsSoFar =
if creditsSoFar == requirement && head path == "math"
then [path]
else do
next <- fromJust (lookup (head path) classes)
guard (next /= "exam"
&& creditsSoFar + fromJust (lookup next credits) <= requirement)
solve' (next:path) (creditsSoFar + fromJust (lookup next credits))
以下是Haskell中的一个版本,从检查室向后生成路径,并丢弃信用总额大于要求的路径:
import Data.Maybe (fromJust)
import Control.Monad (guard)
classes = [("exam",["modeling"])
,("modeling",["exam","stochastic","calculus","math","modern arts"])
,("stochastic",["calculus","modeling"])
,("calculus",["stochastic","modeling","math"])
,("math",["calculus","modeling","algebra"])
,("algebra",["math","philosophy"])
,("philosophy",["algebra","modern arts"])
,("modern arts",["philosophy","modeling"])]
credits = [("exam",0)
,("modeling",29)
,("stochastic",23)
,("calculus",20)
,("math",17)
,("algebra",35)
,("philosophy",32)
,("modern arts",17)]
solve requirement = solve' ["exam"] 0 where
solve' path creditsSoFar =
if creditsSoFar == requirement && head path == "math"
then [path]
else do
next <- fromJust (lookup (head path) classes)
guard (next /= "exam"
&& creditsSoFar + fromJust (lookup next credits) <= requirement)
solve' (next:path) (creditsSoFar + fromJust (lookup next credits))
卡莉能从底门离开数学室,从左门进入考场吗?不能。底门数学室是入口,左门考场是出口。进入考场的唯一途径是通过模拟室凯利必须在他进入的房间上课吗?是的。每次他进入一个房间,它都假设课程已经被录取,他就可以获得学分。所以不管怎样,他都会从数学课开始,获得17个学分,从模特课结束,获得29个学分credits@user1411893希望为下面的两个解决方案添加更好的描述。它们似乎都是回溯算法:。这种想法本质上是一种野蛮的力量。从数学教室开始,试试其他的教室。继续尝试直到失败,然后撤销一个类并尝试其他方法。直观地说,蛮力会让你得到所有答案(如果有的话),但如果图表变大,通常效果不是很好。Karli可以从底部的门离开数学室,从左侧的门进入考试室吗?不。底部的数学室是入口,左侧的考试室是出口。进入考场的唯一途径是通过模拟室凯利必须在他进入的房间上课吗?是的。每次他进入一个房间,它都假设课程已经被录取,他就可以获得学分。所以不管怎样,他都会从数学课开始,获得17个学分,从模特课结束,获得29个学分credits@user1411893希望为下面的两个解决方案添加更好的描述。它们似乎都是回溯算法:。这种想法本质上是一种野蛮的力量。从数学教室开始,试试其他的教室。继续尝试直到失败,然后撤销一个类并尝试其他方法。直观地说,蛮力可以得到所有答案(如果有的话),但如果图变大,通常性能不是很好。我认为这不会提供所有的解决方案,因为一个类可能会被多次使用,这在BFS中是不允许的。@nularman作者@user1411893似乎只需要一个解决方案。但是如果您确实需要所有的解决方案,您可以放弃散列
,只检查积分是否超过214,以便随着队列的增长可以访问所有可能的解决方案。更重要的是,“一个类可能会被执行多次,这在BFS中是不允许的”
是不正确的,这取决于您如何控制排队操作。@nularman实际上我的解决方案已经允许一个类执行多次<代码>外部(0)
->数学(17)
->代数(52)
->现代艺术(69)
->哲学(101)
->代数(136)
哲学(168)
现代艺术(185)
->建模(214)
>考试(214)