POJ_3249 Test for Job(拓扑)

题目请点我
题解:
找到起点到终点的一条最长的路,输出最大的长度。起点定义为入度为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 ;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值