[poj3249]Test For Job

题目大意是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.其它优化....自己想去大笑

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值