题意:

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

思路:

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

    pytorch入门到项目(-) 一.pytorch的环境 本身项目采用win10系统+pycharm+anaconda+cuda. 其中版本为 python 3.7 anaconda 5.3.1 cu ...

  2. xss靶场大通关(持续更新ing)

      xss秘籍第一式(常弹) (1)进入自己搭建的靶场,发现有get请求,参数为name,可进行输入,并会将输入的内容显示于网页页面 (2)使用xss的payload进行通关: http://127. ...

  3. groovy-map.each{}

    ConfigDetail postEdiUrl(TtxSession sess, String code) { return cdSvc.getByRecordTypeAndIdentifier(se ...

  4. python学习总结篇(2)——函数

    如其他语言一样,除了基本知识外,另外一个重要的板块就是函数了,python中也有函数. 在python中,函数的定义方式为: def   函数名( ): 下面通过几个简单的例子,看看python中的函 ...

  5. 树莓派4刷FreeBSD

    树莓派4可以刷FreeBSD了.需要替换boot文件.​加群获得文件QQ交流群817507910.

  6. PTE 准备之 Read aloud

    Read aloud A text appears on screen.Read the text aloud rext up tp 60 words varies by task, dependin ...

  7. 电影AI修复,让重温经典有了新的可能

    摘要:有没有一种呈现,不以追求商业为第一目的,不用花大价钱,不用翻拍,没有画蛇添足,低成本的可共赏的让经典更清晰? 本文分享自华为云社区<除了重映和翻拍,重温经典的第三种可能>,原文作者: ...

  8. WM_CLOSE WM_QUIT WM_DESTROY 三者的区别

    一 个窗口或者应用程序应该被关闭时发出WM_CLOSE消息,当接收到WM_CLOSE消息时,如果你愿意,向用户提出是否真的退出.你知道让用户作确认或 有错误出现或有什么应该注意的事情发生的时候,往往弹 ...

  9. 2021年的UWP(6)——长生命周期Desktop Extension向UWP的反向通知

    上一篇我们讨论了UWP和Desktop Extension间的双向通讯,适用于Desktop Extension中存在用户交互的场景.本篇我们讨论最后一种情况,与前者不同的是,Desktop Exte ...

  10. java例题_49 计算子串出现的次数

    1 /*49 [程序 49 子串出现的个数] 2 题目:计算字符串中子串出现的次数 3 */ 4 5 /*分析 6 * 1.子串的出现是有标志的,如" ",*,#或者其他 7 * ...