zoukankan      html  css  js  c++  java
  • POJ3160强连通+spfa最长路(不错)

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


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


        }
        return 0;
    }







  • 相关阅读:
    13.字符串压缩算法
    12.字符串全部替换指定文本
    46.数字到字符串的转换
    45.切割字符串并精确分配内存
    44.字符串删除指定字符或者字符串
    11.表达式计算对一串加减乘除带括号进行计算
    43.可变参数实现printf
    关于float与double区别
    float,double与long long哪个更大?
    double 与0比较时有个精度问题,有时需精确到小数点后面几位,例如与>0.0001,而不能与>0比较
  • 原文地址:https://www.cnblogs.com/csnd/p/12062465.html
Copyright © 2011-2022 走看看