nyu 的AI课的课后习题
http://cs.nyu.edu/courses/spring12/CSCI-GA.2560-001/prog1.html
题目的大意是输入n个task 每个task都有time(完成时间) value(完成产生的价值) task可能会有先驱 打个比方就是 要先完成task1 才能去进行task2
给定一个targetvalue 和deadline(最后完成时间) 找到一种在deadline时间之前完成的 并且总价值达到targetvalue的解法
首先因为有先驱所以就要进行拓扑排序 。产生一个 topologyResult[]数组
来存储拓扑排序的结果。 然后就对拓扑排序的结果进行BFS , 用state
结构体来存储当前的状态。
state.selected[]:当前状态执行了那些点
state.totalvalue:当前状态的总价值
state.totaltime : 当前状态所用的总时间
state.currentdepth:当前状态 搜索到了topologyResult[]中的点的下标
首先进行BFS 取出队列首部的状态,对topologyResult[]中的每个点进行两种操作 尝试添加该点(
(1).总的time 没有达到了deadline 把这个状态加入队列的尾部 ,、
(2).总的time没有达到deadline 放弃这个状态) 将没有添加该点的状态加入队列的尾部 直到找到 达到targetvalue的状态
在没有找到targetvalue的情况下 队列的长度达到了queueMaxSize就进行 迭代深度优先搜索 在迭代深度优先搜索(IDDFS)中也是同样的
尝试添加该点 (1.总的time没有达到deadline 递归调用深度优先搜索 2.总的time达到了deadline 则不进行递归调用 )然后在没有添加该点的状态下进行递归调用!
#include <stdio.h>
#include <vector>
#include <map>
#include <queue>
using namespace std;
int taskNum;
int targetValue;
int deadline;
int queueMaxSize;
struct State {
bool * selected;
int totalValue;
int totalTime;
int currentDepth;//当前搜索的状态处于哪一层
State(State&a)
{
selected = new bool[taskNum];
for (int i = 0; i < taskNum; i++)
{
selected[i] = a.selected[i];
}
totalValue = a.totalValue;
totalTime = a.totalTime;
currentDepth = a.currentDepth;
}
State()
{
selected = new bool[taskNum];
memset(selected, false, sizeof(selected));
totalValue = 0;
totalTime = 0;
currentDepth = -1;
}
State &operator=(const State &a)
{
for (int i = 0; i < taskNum; i++)
{
selected[i] = a.selected[i];
}
totalValue = a.totalValue;
totalTime = a.totalTime;
currentDepth = a.currentDepth;
}
} ;
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];//对应tipologyResult中的元素有没有bfs过
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];//得到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 =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) {//没有找到结果 添加该点后继续搜索拓扑排序后的下个点
if (DFS(depth - 1, state)) {
return true;
}
}
}
//这里是不能选改层结点对应的递归 0 ,要先把该结点拿出来
state.totalValue -= node.value;
state.totalTime -= node.time;
}
/*
无论在添加currentDepth点后是否满足deadline 都在不添加currentDepth点后进行搜索currentDepth+1的深度
*/
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;
}