今天写了4h的test for job,之所以用了这么长时间是因为一开始的方法出现了问题。
这道题目如果按照一般的动规思想,会想到从下往上的解决方法,也就是从目标城市网上搜索ans[i-1]=max(ans[i-1],ans[i]+value[i-1])的方式进行动规,但是这种方法会有特别极端的情况导致计算量激增。如下图所示。
如果从下往上搜索,很明显,这一条曲曲折折的线条被重复计算了5次,如果底下的分支很大,那么计算量就会增长很快。
所以我们必须采取从上向下的记忆化搜索方式。
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
const int INF = -0x3fffffff;
long long int max(long long int a, long long int b)
{
if (a > b) return a;
return b;
}
struct city
{
int value;
bool first;//记录是不是第一个
};city citys[100005];
vector<int> vnext[100005];//记录城市i的后续城市
int ans[100005];//数组的下标代表城市编号i,代表i到target的最大价值
int search(int k)//自上而下的记忆化搜索
{
if (ans[k] != INF) return ans[k];
if (vnext[k].empty()) return citys[k].value;//如果是最后一个
for (int i = 0; i < vnext[k].size(); ++i)
ans[k] = max(ans[k], search(vnext[k][i]) + citys[k].value);
return ans[k];
}
int main()
{
int city_num = 0, road_num = 0;
while (cin >> city_num >> road_num)
{
for (int i = 1; i <= city_num; ++i)
{
scanf("%d", &citys[i].value);
vnext[i].clear();
ans[i] = INF;
citys[i].first = true;
}
int tmp1 = 0, tmp2 = 0;
for (int i = 0; i < road_num; ++i)
{
scanf("%d%d", &tmp1, &tmp2);
vnext[tmp1].push_back(tmp2);
citys[tmp2].first = false;
}
int MAX = INF;
for (int i = 1; i <= city_num; ++i)
{
if (citys[i].first)//从起始城市开始向下递归
MAX = max(MAX, search(i));
}
printf("%d\n", MAX);
}
return 0;
}
如有错误,希望大家纠正!