算法整理:拓扑排序(1)
问题简述:
每一个节点有一个代价值cost[i],在有向无环图中寻找一个拓扑序最小的序列,并求出最小的拓扑序列和
算法分析:
提示:在拓扑序模板的基础上加入动态规划。代码及注释:
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <stack>
using namespace std;
#pragma warning(disable:4996)
int find(vector<int>& v, int e)
{
for (int i = 0; i<int(v.size()); ++i)
if (e == v[i])
return i+1;
return -1;
}
int main()
{
//freopen("data.txt","r", stdin);
int n;
cin >> n;
vector<vector<int>> v(n+1); //保存每一项工作的准备工作的编号
vector<int> cost(n+1); //保存输入的每一项工作的耗时
vector<int> ans; //ans[i]表示做完第i项工作及其准备工作后的耗时
vector<int> count; //保存每一项工作前驱工作的数量
ans.resize(n+1, 0);
count.resize(n+1, 0);
stack<int> s;//保存当前可以执行的工作的编号
//处理输入
for (int i = 1; i <= n; ++i)
{
int temp;
cin >> temp;
cin >> temp;
cost[i]=(temp); //将每一项工作的耗时都加入数组
while (true) //保存每一项工作的先前工作
{
cin >> temp;
if (temp == 0)
break; //为0表示结束了
else
{
v[i].push_back(temp);
count[i]++;
}
}
}
//拓扑序列模板
//先初始化栈,将不需要准备的工作先加入栈
for (int i = 1; i <= n ; ++i)
if (count[i] == 0)
{
s.push(i);
ans[i] = cost[i];
}
//依次从栈顶中取出元素,每取出一个元素后考虑该元素的贡献,即该元素是哪些工作的准备工作
while (!s.empty())
{
int temp = s.top();
s.pop();
for (int i = 1; i<= n ; ++i)
{
int index = find(v[i], temp);
if (index!= -1)
{
ans[i] = max(ans[i], cost[i] + ans[temp]);
if ((--count[i]) == 0)
s.push(i);
}
}
}
//截止每一项工作的最大耗时就是所需的答案
int max_ans = ans[1];
for (int i = 1; i <= n; ++i)
max_ans = max(max_ans, ans[i]);
cout << max_ans << endl;
return 0;
}