题意:

      给你一个有向图,每个点上有一个权值,可正可负,然后给你一些链接关系,让你找到一个起点,从起点开始走,走过的边可以在走,但是拿过权值的点就不能再拿了,问最多能拿到多少权值?

思路:

      首先我们考虑一个简单的问题,这个题目的负权值点肯定不拿,对于一个环(应该说是一个强连通分量)来说要拿可以一下全拿走(这个自己黄画画),那么一个环的价值是多少?就是这个强连通分量里所有正权值的和,这样我们一边强连通缩点,缩点之后变成了一个无环的有向图,然后在在上面跑最长路就行了,还有提醒一点,题目说的起点不固定,这个也好处理,我们只要在虚拟出来一个起点,到所有点的权值都是0就行了,这样就能一遍spfa搞定了,千万别跑n遍spfa那样太无脑了。

虽然简单,但感觉这个题目还不错,挺有实际意义的。

#include<stack>

#include<queue>

#include<stdio.h>

#include<string.h>

#define N_node 30000 + 10

#define N_edge 200000 + 50

#define INF 1000000000

using namespace std;

typedef struct

{

    int to ,cost ,next;

}STAR;

typedef struct

{

    int a ,b;

}EDGE;

EDGE E[N_edge];

STAR E1[N_edge] ,E2[N_edge];

int list1[N_node] ,list2[N_node] ,tot;

int Belong[N_node] ,mark[N_node] ,cont;

int s_x[N_node] ,get[N_node] ,cost[N_node];

stack<int>sk;

void add(int a ,int b ,int c)

{

    E1[++tot].to = b;

    E1[tot].cost = c;

    E1[tot].next = list1[a];

    list1[a] = tot;

    E2[tot].to = a;

    E2[tot].cost = c;

    E2[tot].next = list2[b];

    list2[b] = tot;

}

void DFS1(int s)

{

    mark[s] = 1;

    for(int k = list1[s] ;k ;k = E1[k].next)

    if(!mark[E1[k].to]) DFS1(E1[k].to);

    sk.push(s);

}

void DFS2(int s)

{

    mark[s] = 1;

    Belong[s] = cont;

    for(int k = list2[s] ;k ;k = E2[k].next)

    if(!mark[E2[k].to]) DFS2(E2[k].to);

}

void Spfa(int s ,int n)

{

    memset(mark ,0 ,sizeof(mark));

    for(int i = 0 ;i <= n ;i ++)

    s_x[i] = -INF;

    queue<int>q;

    q.push(s);

    mark[s] = 1;

    s_x[s] = 0;

    while(!q.empty())

    {

        int xin ,tou;

        tou = q.front();

        q.pop();

        mark[tou] = 0;

        for(int k = list1[tou] ;k ;k = E1[k].next)

        {

            xin = E1[k].to;

            if(s_x[xin] < s_x[tou] + E1[k].cost)

            {

                s_x[xin] = s_x[tou] + E1[k].cost;

                if(!mark[xin])

                {

                    mark[xin] = 1;

                    q.push(xin);

                }

            }

        }

    }

}

int main ()

{

    int n ,m ,i ,a ,b;

    while(~scanf("%d %d" ,&n ,&m))

    {

        for(i = 1 ;i <= n ;i ++)

        scanf("%d" ,&cost[i]);

        memset(list1 ,0 ,sizeof(list1));

        memset(list2 ,0 ,sizeof(list2));

        tot = 1;

        for(i = 1 ;i <= m ;i ++)

        {

            scanf("%d %d" ,&a ,&b);

            a ++ ,b ++;

            add(a ,b ,1);

            E[i].a = a ,E[i].b = b;

        }

        while(!sk.empty()) sk.pop();

        memset(mark ,0 ,sizeof(mark));

        for(i = 1 ;i <= n ;i ++)

        if(!mark[i]) DFS1(i);

        memset(mark ,0 ,sizeof(mark));

        cont = 0;

        while(!sk.empty())

        {

            int to = sk.top();

            sk.pop();

            if(mark[to]) continue;

            ++cont;

            DFS2(to);

        }

        memset(get ,0 ,sizeof(get));

        for(i = 1 ;i <= n ;i ++)

        if(cost[i] >= 0) get[Belong[i]] += cost[i];

        memset(list1 ,0 ,sizeof(list1));

        memset(list2 ,0 ,sizeof(list2));

        tot = 1;

        for(i = 1 ;i <= n ;i ++)

        add(0 ,i ,get[i]);

        for(i = 1 ;i <= m ;i ++)

        {

            a = Belong[E[i].a];

            b = Belong[E[i].b];

            if(a == b) continue;

            add(a ,b ,get[b]);

        }

        Spfa(0 ,n);

        int ans = 0;

        for(i = 1 ;i <= n ;i ++)

        if(ans < s_x[i]) ans = s_x[i];

        printf("%d\n" ,ans);

    }

    return 0;

}

POJ3160强连通+spfa最长路(不错)的更多相关文章

  1. 【bzoj1179】[Apio2009]Atm Tarjan缩点+Spfa最长路

    题目描述 输入 第一行包含两个整数N.M.N表示路口的个数,M表示道路条数.接下来M行,每行两个整数,这两个整数都在1到N之间,第i+1行的两个整数表示第i条道路的起点和终点的路口编号.接下来N行,每 ...

  2. bzoj1179: [Apio2009]Atm 【缩点+spfa最长路】

    题目传送门 Description Siruseri 城中的道路都是单向的.不同的道路由路口连接.按照法律的规定, 在每个路口都设立了一个 Siruser i 银行的 ATM 取款机.令人奇怪的是,S ...

  3. XYZZY spfa 最长路 判环

    题意: 有n个点  m条边  每个边有权值 一开始有一百血  每次经过一条路都会加上其权值 判断是否能够到达n 显然  有正环的时候肯定能够到达 最短路好题!!!!!!! 显用folyed判断是否联通 ...

  4. poj 1932 XYZZY(spfa最长路+判断正环+floyd求传递闭包)

    XYZZY Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 4154   Accepted: 1185 Description ...

  5. HDU 6201 2017沈阳网络赛 树形DP或者SPFA最长路

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6201 题意:给出一棵树,每个点有一个权值,代表商品的售价,树上每一条边上也有一个权值,代表从这条边经过 ...

  6. Tarjan缩点+Spfa最长路【p3627】[APIO2009] 抢掠计划

    Description Siruseri 城中的道路都是单向的.不同的道路由路口连接.按照法律的规定, 在每个路口都设立了一个 Siruseri 银行的 ATM 取款机.令人奇怪的是,Siruseri ...

  7. [BZOJ1663] [Usaco2006 Open]赶集(spfa最长路)

    传送门 按照时间t排序 如果 t[i] + map[i][j] <= t[j],就在i和j之间连一条边 然后spfa找最长路 #include <queue> #include &l ...

  8. [luogu3627 APIO2009] 抢掠计划 (tarjan缩点+spfa最长路)

    传送门 Description Input 第一行包含两个整数 N.M.N 表示路口的个数,M 表示道路条数.接下来 M 行,每行两个整数,这两个整数都在 1 到 N 之间,第 i+1 行的两个整数表 ...

  9. BZOJ 3887/Luogu P3119: [Usaco2015 Jan]Grass Cownoisseur (强连通分量+最长路)

    分层建图,反向边建在两层之间,两层内部分别建正向边,tarjan缩点后,拓扑排序求一次1所在强连通分量和1+n所在强联通分量的最长路(长度定义为路径上的强联通分量内部点数和).然后由于1所在强连通分量 ...

随机推荐

  1. 漏洞复现-CVE-2018-15473-ssh用户枚举漏洞

          0x00 实验环境 攻击机:Win 10 0x01 影响版本 OpenSSH 7.7前存在一个用户名枚举漏洞,通过该漏洞,攻击者可以判断某个用户名是否存在于目标主机 0x02 漏洞复现 针 ...

  2. Java数组:初识数组

    数组:数组是相同类型数据的有序集合数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成其中,每一个数据称作一个数组元素,每个数组元素可以通过一个下标来访问他们 数组基本特点:其长度是确定的 ...

  3. ACM常用的C++ && STL

    内容 c++输入输出 c++ string vector:不定长数组 map:映射 queue:队列 sort:排序 priority_queue:优先队列 c++输入输出 1 #include &l ...

  4. Python中异步协程的使用方法介绍

    1. 前言 在执行一些 IO 密集型任务的时候,程序常常会因为等待 IO 而阻塞.比如在网络爬虫中,如果我们使用 requests 库来进行请求的话,如果网站响应速度过慢,程序一直在等待网站响应,最后 ...

  5. 面向对象进阶时,if语句写错位置

    这周blog我也不知道要写什么,因为这章我其实学得有点懵,前面那几天我纠结了好久代码,一直不知道原因错在哪里.后来经过询问老师才知道自己调用错了构造方法,相信也有跟我一样的新手会犯这个错误.我在创建关 ...

  6. Asp.Net Core 学习随笔

    1.依赖注入 configureServices 中 //单例 services.AddSingleton<i,c>(); //http请求内 services.AddScopend< ...

  7. Python基础之异常定义

    技术背景 在各类python的项目中,总会涉及到项目自身相关的一些约束条件.这些约束条件体现在,当用户输入的参数或者文件不符合项目要求时,就拒绝这个参数的输入并且播报出来,提醒用户自行修改,而这一过程 ...

  8. mysql中FIND_IN_SET函数用法

    本篇文章主要介绍mysql中FIND_IN_SET函数用法,用来精确查询字段中以逗号分隔的数据 以及其与 like 和 in 的区别 1.问题发现 之前在做工作任务时有这么一个需求:需要用接口所传的服 ...

  9. 第7 章 : 应用编排与管理:Job & DaemonSet

    应用编排与管理:Job & DaemonSet 本节课程要点 Job & CronJobs 基础操作与概念解析: DaemonSet 基础操作与概念解析. Job 需求来源 Job 背 ...

  10. 全网最详细的Linux命令系列-cd命令

    Linux cd 命令可以说是Linux中最基本的命令语句,其他的命令语句要进行操作,都是建立在使用 cd 命令上的. 所以,学习Linux 常用命令,首先就要学好 cd 命令的使用方法技巧. 命令格 ...