NYU AI作业习题-活动安排问题 BFS+DFS Iterative deepening depth-first search

题目链接 http://cs.nyu.edu/courses/spring12/CSCI-GA.2560-001/prog1.html

题目大意:给定n个任务的时间、价值及先后序关系,求一个可行的任务子集,使得时间之和不大于deadline,价值之和不小于targetVaule,且不可出现逆序。

算法思路:题目已经给出算法,转化为状态空间搜索问题(tree-structured state space search problem),先对结点拓扑排序,存储前序的结点关系,然后先对状态搜索树进行BFS,可行的状态压入队列,到达到限制值后,再以队列中的状态为起点进行迭代深入搜索(Iterative deepening depth-first search)。迭代深入搜索算法就是从状态空间搜索树中某一结点如根结点开始,多次迭代DFS,每次DFS设置最大搜索深度depth,depth不断递增至搜索至树叶,伪代码如下

IDDFS(root, goal) { depth = 0 repeat { result = DLS(root, goal, depth) if (result is a solution) return result depth = depth + 1 } }
DLS(node, goal, depth) { if (depth == 0 and node == goal) return node else if (depth > 0) for each child in expand(node) DLS(child, goal, depth-1) else return no-solution }
迭代深入搜索算法具体参见维基百科http://en.wikipedia.org/wiki/Iterative_deepening_depth-first_search

此题求解源代码如下

//http://cs.nyu.edu/courses/spring12/CSCI-GA.2560-001/ #include <stdio.h> #include <vector> #include <map> #include <queue> using namespace std; int taskNum; int targetValue; int deadline; int queueMaxSize; typedef struct { bool * selected; int totalValue; int totalTime; int currentDepth;//当前搜索的状态处于哪一层 } State; typedef struct{ int time; int value; } Node; //记录某点的前序结点(即在执行该任务前必须完成的任务) map<int,vector<int> *> nodesPre; int ** edges; Node * nodes; int * topologyResult;//拓扑排序的结果数组,记录状态树每一层对应的点的标号 int * nodeToTopNode; queue<int> q;//用于拓扑排序 queue<State> stateQ;//用于状态空间搜索的队列 State resState;//搜索到的结果状态 bool hasResult; void initialState(State &state){ state.selected = new bool[taskNum]; memset(state.selected, false, sizeof(state.selected)); state.currentDepth = -1; state.totalTime = 0; state.totalValue = 0; } State copyState(State &state){ State newState; newState.selected = new bool[taskNum]; for(int i = 0; i < taskNum; i++){ newState.selected[i] = state.selected[i]; } newState.currentDepth = state.currentDepth; newState.totalTime = state.totalTime; newState.totalValue = state.totalValue; return newState; } bool checkPreNode(bool * selected, int nodeID){ vector<int> * v = nodesPre[nodeID]; if(v == NULL){ return true; } vector<int>::iterator it = v->begin(); for(;it != v->end(); it++){//遍历该点所有的前序结点,有任何一个结点没有选择都返回false //nodeToTopNode映射数组填入原始标号,可以映射成拓扑排序后的新标号 if(selected[nodeToTopNode[*it]] == false) return false; } return true; } bool BFS(){ State root;//初始状态空间树的搜索起点,即根节点 initialState(root); stateQ.push(root); hasResult = false; while(!stateQ.empty()){ if(stateQ.size() == queueMaxSize){ //当该层结点可以选择时,就会压入两个状态,弹出一个状态,因此状态队列会越来越大 //达到最大队列限制后跳出BFS,开始进行迭代深度优先搜索IDS break; } State state = stateQ.front(); stateQ.pop(); State tempSubState = copyState(state); if(tempSubState.currentDepth == taskNum - 1){ continue; } tempSubState.currentDepth++; int nodeID = topologyResult[tempSubState.currentDepth]; //下面检查该点之前的结点是否都已经选择,且累计的value和time是否满足要求 if(checkPreNode(tempSubState.selected, nodeID) == true){ Node tempNode = nodes[nodeID]; tempSubState.selected[tempSubState.currentDepth] = true; tempSubState.totalTime += tempNode.time; tempSubState.totalValue += tempNode.value; if(tempSubState.totalTime <= deadline){ stateQ.push(tempSubState); if(tempSubState.totalValue >= targetValue){ hasResult = true; resState = copyState(tempSubState); break; } } } //如果当前层结点可以选(没有出现未选的前序结点),就一共压入了两个状态入队列(选和不选); //否则就压入一个状态即不选改层结点的状态 State tempSubState2 = copyState(state); tempSubState2.currentDepth++; tempSubState2.selected[tempSubState2.currentDepth] = false; stateQ.push(tempSubState2); } return hasResult; } bool DFS(int depth, State state){//最大深度为depth,起始结点对应的状态state state.currentDepth++; int nodeID = topologyResult[state.currentDepth]; if(checkPreNode(state.selected,nodeID) == true){ Node node = nodes[nodeID]; state.selected[state.currentDepth] = true; state.totalValue += node.value; state.totalTime += node.time; if(state.totalTime <= deadline ){ if(state.totalValue >= targetValue ){ resState = copyState(state); return true; } if(depth != 1){//这里是选该层结点对应的递归 1 if(DFS(depth-1,state)){ return true; } } } //这里是不能选改层结点对应的递归 0 ,要先把该结点拿出来 state.totalValue -= node.value; state.totalTime -= node.time; } state.selected[state.currentDepth] = false; if(depth != 1){ if(DFS(depth-1,state)){ return true; } } return false; } bool IDS(){ while(!stateQ.empty()){ State tempstate = stateQ.front(); stateQ.pop(); for(int i = 1; i <= taskNum - (tempstate.currentDepth + 1); i++){//i为最大的搜索深度 if(DFS(i,tempstate)) return true; } } return false; } bool findNoInDegreeNode(int i){ bool hashInDegree = false; for(int j = 0; j < taskNum; j++){ if(edges[j][i]) hashInDegree = true; } return hashInDegree; } void topologySort(){ for(int i = 0; i < taskNum; i++){ if(findNoInDegreeNode(i) == false) q.push(i); } int j,count = 0; while(!q.empty()){ j = q.front(); q.pop(); topologyResult[count] = j; count++; for(int k = 0; k < taskNum; k++){ if(edges[j][k]) { edges[j][k] = 0; if(findNoInDegreeNode(k) == false) q.push(k); } } } printf("拓扑排序结果为"); for(int m = 0; m < taskNum; m++){ nodeToTopNode[topologyResult[m]] = m;//填入原始标号,可以映射成拓扑排序后的新标号 printf("%d ",topologyResult[m]); } } void input(){ scanf("%d%d%d%d",&taskNum,&targetValue,&deadline,&queueMaxSize); nodes = new Node[taskNum]; edges = new int* [taskNum]; topologyResult = new int[taskNum]; nodeToTopNode = new int[taskNum]; for(int j = 0; j < taskNum; j++){ edges[j] = new int[taskNum]; for(int k = 0; k < taskNum; k++){ edges[j][k] = 0; } } int tempNum,preNode,lastNode; for(int i = 0; i < taskNum; i++){ scanf("%d%d%d",&tempNum,&nodes[i].value,&nodes[i].time); } while(true){ scanf("%d",&preNode); if(preNode == -1) break; scanf("%d",&lastNode); edges[preNode][lastNode] = 1; vector<int> * v = nodesPre[lastNode];//v指向lastNode对应的vector容器 if(v == NULL){ v = new vector<int>; nodesPre[lastNode] = v; } v->push_back(preNode); } } void output(){ printf("求得的解为:["); for(int i=0;i<taskNum;i++){ if(resState.selected[i] == 1){//注意结果state中第四项没有赋值,也是非零数 printf(" %d ",topologyResult[i]); } } printf("] %d %d\n",resState.totalValue,resState.totalTime); } int main(){ input(); topologySort(); if(!BFS() && !IDS()){ printf("no solutions"); } else output(); return 0; }
测试代码

#include <iostream> #include <algorithm> #include <functional> #include <vector> #include <ctime> #include <cstdlib> #include <cmath> #define MAXN 500 using namespace std; int main(){ int n, e = 1000, r[MAXN], v[MAXN], maxLen,p[MAXN]; int i,j,D,M,minVD,maxVD,k=0; int DAG[MAXN][MAXN] = {0}; cout<<"Please input the number of tasks in each example( less than 500)"<<endl; cin>>n; srand ( unsigned ( time (NULL) ) ); for(i = 0; i < n; i++){ r[i] = rand() % n + 1; v[i] = rand() % n + 1; } minVD = n * n * (1 - 2/sqrt(n))/4; maxVD = n * n * (1 + 2/sqrt(n))/4; D = rand() % (maxVD - minVD) + minVD + 1; M = rand() % (maxVD - minVD) + minVD + 1; maxLen = rand() % n + 1;//队列最大长度 //下面随机生成DAG vector<int> myvector; vector<int>::iterator it; for (i = 0; i < n; ++i) myvector.push_back(i); random_shuffle ( myvector.begin(), myvector.end() ); cout << "myvector contains:"; for (it=myvector.begin(); it!=myvector.end(); ++it){ cout << " " << *it << ","; p[k] = *it; k++; } cout<<endl; cout<<"r[]:"; for(i = 0; i < n; i++){ cout<<r[i] << ","; } cout<<endl; cout<<"v[]:"; for(i = 0; i < n; i++){ cout<<v[i] << ","; } cout<<endl; cout<<"D:"<<D<<endl<<"M:"<<M<<endl; for(i = 0; i < n-1; i++)//遍历的其实是数组 for(j = i+1; j <n; j++){ DAG[p[i]][p[j]] = rand() % 2; if(DAG[p[i]][p[j]]) cout<<p[i]<<" "<<p[j]<<endl; } for(i = 0; i < n; i++){ for(j = 0; j < n; j++){ cout<<DAG[i][j]<<" "; } cout<<endl; } cout<<endl; cout<<"the input for this example is as follows"<<endl; cout<<n<<" "<<M<<" "<<D<<" "<<maxLen<<endl; for(i = 0; i < n; i++){ cout<<i<<" "<<v[i]<<" "<<r[i]<<endl; } for(i = 0; i < n; i++){ for(j = 0; j < n; j++){ if(DAG[i][j]) cout<<i<<" "<<j<<endl; } } cout<<endl; return 0; }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值