题目大意是JB应聘喷到变态老板,让他做一个变态题.题目要求它在城市间旅游,城市间的道路是单向的,没有环,没有回路,也没有重边的样子.傻逼老板让JB从所谓的Source City搞呀搞
最后要搞到一个耙城市(直译).这源城市奏是俺们俗称"源点"的了,耙城市奏是俺们俗称的汇点.
翻译成俺们好理解的语言奏是:JB要从一个有向无环图中的某个入度为0的点沿有向边走到某个出度为0的点.边没有边权,但是点有"点权",而且可以为负数.当然了题目的测试数据还
包括"孤立点"这种傻逼反人类trick.谁没事会折腾这个呀....我在起点,所以我在终点???好有哲理的样子.
这题说是dp+拓扑排序.其实完全是拓扑排序的一点小拓展.没有甚么难想的状态\转移方程等等...
我们只要拓扑排序就好了,然后在拓扑的过程中,用入度为0的点去更新和它连有边的点就好了,而且只能更新那些由这个入度为0的点有向外的有向边的点哦~~~
如果你不费拓扑排序,千万不要觉得这名字好屌而害怕,其实思想超级简单,...呃呃呃,我突然有一种想写篇拓扑排序的入门文章,你想看嘛?那我写好了把地址留在下面的留言里好了~~
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int INF = -0xfffffff;
const int MAX = 100000+111;
vector<int> G[MAX];
int in[MAX], out[MAX]; //入度,出度
int val[MAX]; //点加权
int dp[MAX]; //dp.设有边ui->vi,则dp[v] = max{dp[v], dp[ui]+val[v]}
int Stack[MAX], Top; //STL的栈太慢,这里不需要那么好的安全性能,为了速度,自己数组搞
int StackAns[MAX], TopAns; //这个栈保存出度为0的点,可以在最后找答案时节省些许时间,
//去掉也行,最后遍历一遍0~n-1也是一样的
int n, m;
int main() {
while (~scanf(" %d %d", &n, &m)) {
/* init */
memset(in, 0, sizeof(in));
memset(out, 0, sizeof(out));
register int i, j;
for (i = 0; i < n; ++i) {
scanf(" %d", val+i);
//dp[i] = val[i];
G[i].clear();
}
int f, t;
for (i = 0; i < m; ++i) {
scanf(" %d %d", &f, &t);
--f, --t; //统一下标为0~n-1
G[f].push_back(t);
++in[t], ++out[f];
}
/* 然后要拓扑一下,所以需要一个工作栈或者工作数组来记录 */
/* 这里就用Stack数组来记录了,Top既表示栈顶也表示栈中元素个数 */
/* 初始化工作栈 */
Top = TopAns = 0;
for (i = 0; i < n; ++i) {
if (!in[i]) {
Stack[Top++] = i;
dp[i] = val[i];
} else dp[i] = INF;//dp数组的初始化需要注意.如果入度为0,则初始化val[i].否则无穷小
//原因:举例两个点0->1,两点收益分别是-1,2.那么如果入度不为0的
//点1初始化成2,我们拓扑排序用点0更新1的答案仍为2.
//但是题目有个很强的限制要求:*必须*从入度为0的点出发到达出度为0
//的点.这里WA了好几次(=@__@=)...
if (!out[i]) StackAns[TopAns++] = i; //把出度为0的编号保存,加速最后的答案更新
}
/* 拓扑n次 */
int td, dong;
for (i = 0; i < n; ++i) {
if (!Top) break;
td = Stack[--Top];
for (j = 0; j < G[td].size(); ++j) {
dong = G[td][j];
dp[dong] = max(dp[dong], dp[td] + val[dong]);
--in[dong];
if (!in[dong]) { //这题数据大,我真的不是有意要写成!in[dong]这么难理解的丫...
Stack[Top++] = dong;
}
}
}
int ans = INF;
while (TopAns--) {
if (dp[StackAns[TopAns]] > ans) ans = dp[StackAns[TopAns]];
}
printf("%d\n", ans);
}
return 0;
}
代码只加了一些可能会让人费解的地方的注释~~其中的思路过程并不复杂,如果你是想看题解而看到了,建议你带着这个思路自己去实现自己的程序,千万不要对着代码敲(除非你
认为这是个好办法).
这题的优化,我认为首先vector数组的部分可能需要优化,很费时间的,昨天那题就是因为vector的用量太大,直接导致TLE.其它优化....自己想去