查找路径的算法(计划类)

时间:2013-05-26 00:56:49

标签: algorithm graph graph-traversal

我正在试图弄清楚如何解决这个问题..这是从为12年级学生举办的编程竞赛中获取的。 任务是让学生'Karli'参加足够的课程以获得214学分。在进入考场之前,学生不能多于或少于214学分。门在图中表示。用户可以为其他课程重复上课,但他们必须离开那个教室......去另一个教室......然后回来。

我尝试手动执行此操作,并且能够找到一个带路径的解决方案:

数学代数的理念代数-数学建模演算建模考试

我正在尝试开发一种算法,该算法将根据所需的信用数量找到一条路径(即本案例为214)

这是我尝试过的东西并且坚持下去:

将地图表示为图形,门是两个节点之间的双边。但是我不知道哪种图形遍历算法可以让我解决这个问题呢?

将图形转换为邻接矩阵会使事情变得更容易吗?

谢谢

2 个答案:

答案 0 :(得分:1)

Breadth First Search将解决此问题。

当Karli到达编号为(room, credit)且信用值记录在room的房间时,记录状态credit

使用queue维护数据。在开始时,只有(外部,0)在队列中。每次弹出头部,然后从head描述的状态移至head的每个邻居房间,然后计算新状态并将其推送到queue的末尾(请记住使用哈希来避免多次添加相同的状态)。

当您达到状态(exam, 214)时,展开过程就会完成。剩下的工作是从状态(exam, 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");
}

UPD1:抱歉,我在为neighbour[]分配值时犯了一些错误。我解决了它。

UPD1:抱歉,进入考场时,我忘记检查学分是否为214。我解决了它。

UPD3:@Nuclearman表示它没有提供所有解决方案。我们只需要从代码中删除hash,并在使用credit 214生成新状态时计算路径。我在此处提供新代码。

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 outputpath(){
        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");
}

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;
                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;
                        Q.push_back(tmp);
                        pred.push_back(f);
                        if(tmp.credit==214 && tmp.pos==0){
                                outputpath();
                                /* uncomment the next line to get only one solution*/
                                //found = true;
                                break;
                        }
                }
                if(found)break;
        }
}

答案 1 :(得分:0)

这是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))

输出:

*Main> solve 214
[["math","algebra","philosophy","algebra","math","modeling","calculus","modeling","exam"]
,["math","calculus","math","calculus","math","calculus","math","calculus","math","calculus","modeling","exam"]
,["math","algebra","philosophy","modern arts","philosophy","algebra","math","modeling","exam"]]
(0.19 secs, 9106396 bytes)