题目请点我
题解:
找到起点到终点的一条最长的路,输出最大的长度。起点定义为入度为0的点,重点定义为出度为0的点。
拓扑排序的题目,每次找到入度为0的点去更新,然后把权值往后叠加。这样能把所有的路径考虑到并且当遇到交叉节点时能保存较大值,题目数据量比较大,搜索是会超时的。注意因为存在权值为负的边,所以在更新的时候要注意。
测试数据:
7 7
1 2 3 -100 5 6 7
1 2
1 3
2 3
2 4
3 4
4 5
6 7
4 5
-1 -2 -3 -4
1 2
1 3
2 3
3 4
2 4
代码实现:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#define MAX_N 100010
#define MAX_M 1000010
#define INF 0x7fffffff
using namespace std;
int N,M;
bool flag;
int result;
int add[MAX_N];
//点的权值
int value[MAX_N];
int indegree[MAX_N];
queue<int> TD;
//储存边的权值
vector<int> point[MAX_N];
//更新队列,找到入度为0的点
void refresh();
int main()
{
//freopen("in.txt","r",stdin);
while( scanf("%d%d",&N,&M) != EOF ){
int a,b;
flag = true;
result = -INF;
//注意赋为最小值,因为存在负边
//memset(add,0,sizeof(add));
fill(add,add+N+1,-INF);
memset(indegree,0,sizeof(indegree));
//更新vector很重要
for( int i = 1; i <= N; i++ ){
scanf("%d",&value[i]);
point[i].clear();
}
for( int i = 0; i < M; i++ ){
scanf("%d%d",&a,&b);
point[a].push_back(b);
indegree[b]++;
}
while( true ){
//每次都要更新
refresh();
//没有顶点时跳出
if( TD.empty() ){
break;
}
while( !TD.empty() ){
int start = TD.front();
//更新点上的权值为能到达当前点的最大值
value[start] += add[start];
indegree[start]--;
TD.pop();
//出度为0表示终点
int len = point[start].size();
if( len == 0 ){
result = max(value[start],result);
}
for(int i = 0; i < len; i++ ){
int to = point[start][i];
indegree[to]--;
//更新
add[to] = max(add[to],value[start]);
}
}
}
printf("%d\n",result);
}
return 0;
}
void refresh(){
//起点的附加权值为0
for( int i = 1; i <= N ; i++ ){
if( indegree[i] == 0 ){
TD.push(i);
if( flag ){
add[i] = 0;
}
}
}
flag = false;
return ;
}