BZOJ 1179 APIO 2009 Atm Tarjan+SPFA

题目大意:给出一张有向图,每一个节点有一个权值,经过一次之后会取走节点上的权值。有一个原点,多个汇点,问最多能收获多少权值。

思路:做一次Tarjan将图变成拓扑图,然后直接跑SPFA+Heap,比较慢,但是用了高大上的namespace,很开心。

CODE:

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 500000
using namespace std;

struct Complex{
    int pos,len;

    Complex(int _,int __):pos(_),len(__) {}
    bool operator <(const Complex &a)const {
        return len < a.len;
    }
};

int points,edges,cnt;
int head[MAX],total;
int next[MAX],aim[MAX];
int src[MAX];
int S,T;

int deep[MAX],low[MAX],_total;
bool v[MAX];
int changed[MAX],sum[MAX],scc;
int stack[MAX],top;
bool in_stack[MAX];

namespace SPA{
    int head[MAX],total;
    int next[MAX],aim[MAX];

    int f[MAX];

    inline void Add(int x,int y)
    {
        next[++total] = head[x];
        aim[total] = y;
        head[x] = total;
    }

    int SPFA(int st,int ed)
    {
        static priority_queue<Complex> q;
        q.push(Complex(st,sum[st]));
        f[st] = sum[st];
        while(!q.empty()) {
            Complex temp = q.top(); q.pop();
            int x = temp.pos;
            if(f[x] > temp.len)  continue;
            for(int i = head[x]; i; i = next[i])
                if(f[aim[i]] < f[x] + sum[aim[i]]) {
                    f[aim[i]] = f[x] + sum[aim[i]];
                    q.push(Complex(aim[i],f[aim[i]]));
                }
        }
        return f[ed];
    }
}

inline void Add(int x,int y)
{
    next[++total] = head[x];
    aim[total] = y;
    head[x] = total;
}

void Tarjan(int x)
{
    deep[x] = low[x] = ++_total;
    v[x] = true;
    stack[++top] = x;
    in_stack[x] = true;
    for(int i = head[x]; i; i = next[i]) {
        if(!v[aim[i]])
            Tarjan(aim[i]),low[x] = min(low[x],low[aim[i]]);
        else if(in_stack[aim[i]])
            low[x] = min(low[x],deep[aim[i]]);
    }
    if(low[x] == deep[x]) {
        ++scc;
        int temp;
        do {
            temp = stack[top--];
            in_stack[temp] = false;
            sum[scc] += src[temp];
            changed[temp] = scc;
        }while(temp != x);
    }
}

int main()
{
    cin >> points >> edges;
    for(int x,y,i = 1; i <= edges; ++i) {
        scanf("%d%d",&x,&y);
        Add(x,y);
    }
    for(int i = 1; i <= points; ++i)
        scanf("%d",&src[i]);
    for(int i = 1; i <= points; ++i)
        if(!v[i])
            Tarjan(i);
    for(int x = 1; x <= points; ++x)
        for(int i = head[x]; i; i = next[i])
            if(changed[x] != changed[aim[i]])
                SPA::Add(changed[x],changed[aim[i]]);
    cin >> S >> cnt;
    for(int x,i = 1; i <= cnt; ++i) {
        scanf("%d",&x);
        SPA::Add(changed[x],scc + 1);
    }
    cout << SPA::SPFA(changed[S],scc + 1) << endl;
    return 0;
}

时间: 2024-10-07 09:41:54

BZOJ 1179 APIO 2009 Atm Tarjan+SPFA的相关文章

[BZOJ 1179][APIO 2009]Atm

题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1179 个人感觉此题比省选题简单多了,大概是POJ中档题的难度... 首先我们把这个有向图缩个点,缩点后的图是个DAG,新图中每个点的权值是对应强连通分量中的点的权值之和,新图中每个点对应的强连通分量中的点都是相互可达的,也就是说新图中的每个点,劫匪都能一次性抢完其中所有ATM机的钱. 然后对这个新图跑SPFA,SPFA本来是搞边权的,在这个题里,把SPFA稍微改改就能跑点权了,类

bzoj 1179[Apio2009]Atm (tarjan+spfa)

题目 输入 第一行包含两个整数N.M.N表示路口的个数,M表示道路条数.接下来M行,每行两个整数,这两个整数都在1到N之间,第i+1行的两个整数表示第i条道路的起点和终点的路口编号.接下来N行,每行一个整数,按顺序表示每个路口处的ATM机中的钱数.接下来一行包含两个整数S.P,S表示市中心的编号,也就是出发的路口.P表示酒吧数目.接下来的一行中有P个整数,表示P个有酒吧的路口的编号 输出 输出一个整数,表示Banditji从市中心开始到某个酒吧结束所能抢劫的最多的现金总数. 样例输入 6 7 1

【BZOJ-1179】Atm Tarjan + SPFA

1179: [Apio2009]Atm Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 2407  Solved: 993[Submit][Status][Discuss] Description Input 第一行包含两个整数N.M.N表示路口的个数,M表示道路条数.接下来M行,每行两个整数,这两个整数都在1到N之间,第i+1行的两个整数表示第i条道路的起点和终点的路口编号.接下来N行,每行一个整数,按顺序表示每个路口处的ATM机中的钱数.接下来

BZOJ 1295 SCOI 2009 最长距离 SPFA

题目大意:给出一张地图,上面有些点有障碍物,现在有T个机会能够移除障碍物,问地图上最长的欧几里得距离是多长. 思路:在原图的基础上建图,f[i]表示的是起点到这里最少需要移除多少个障碍物,然后暴力枚举起点,更新答案即可. CODE: #include <map> #include <queue> #include <cmath> #include <cstdio> #include <iomanip> #include <cstring&g

【BZOJ 1179】[Apio2009]Atm

[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] tarjan强连通缩点一下. 然后把缩点之后,每个点的钱的数累加起来. 然后从S出发 开始一边做bfs一遍做dp. 最后输出有酒吧的点的dp值中的最大值. [代码] /* n个点,m条有向边. 把有向图G的环进行缩点; 缩完之后的图存在vector <int> g[N]里面; n变为缩完点之后的图的节点的个数了. */ #include <bits/stdc++.h> using namespace std; #d

[BZOJ 1179]ATM题解 Tarjan缩点+SPFA

[BZOJ 1179]ATM题解 Tarjan缩点+SPFA Description Input 第一行包含两个整数N.M.N表示路口的个数,M表示道路条数.接下来M行,每行两个整数,这两个整数都在1到N之间,第i+1行的两个整数表示第i条道路的起点和终点的路口编号.接下来N行,每行一个整数,按顺序表示每个路口处的ATM机中的钱数.接下来一行包含两个整数S.P,S表示市中心的编号,也就是出发的路口.P表示酒吧数目.接下来的一行中有P个整数,表示P个有酒吧的路口的编号 Output 输出一个整数,

BZOJ 1179 Atm 题解

BZOJ 1179 Atm 题解 SPFA Algorithm Tarjan Algorithm Description Input 第一行包含两个整数N.M.N表示路口的个数,M表示道路条数.接下来M行,每行两个整数,这两个整数都在1到N之间,第i+1行的两个整数表示第i条道路的起点和终点的路口编号.接下来N行,每行一个整数,按顺序表示每个路口处的ATM机中的钱数.接下来一行包含两个整数S.P,S表示市中心的编号,也就是出发的路口.P表示酒吧数目.接下来的一行中有P个整数,表示P个有酒吧的路口

[bzoj 1911][Apio 2010]特别行动队(斜率优化DP)

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1911 分析: 首先可以的到裸的方程f[i]=max{f[j]+a*(Si-Sj)^2+b*(Si-Sj)+c} 0<j<i 简化一下方程,我们知道对于一次项,最后结果肯定是b*Sn 所以可以写成f[i]=max{f[j]+a*(Si-Sj)^2+c} 0<j<i 我们不妨设0<x<y<i,且x比y优 即f[x]+a*(Si-Sx)^2+c>f[y]+a*

[BZOJ 1879][SDOI 2009]Bill的挑战 题解(状压DP)

[BZOJ 1879][SDOI 2009]Bill的挑战 Description Solution 1.考虑状压的方式. 方案1:如果我们把每一个字符串压起来,用一个布尔数组表示与每一个字母的匹配关系,那么空间为26^50,爆内存: 方案2:把每一个串压起来,多开一维记录匹配字符,那么空间为nlen26,合法,但不便于状态的设计和转移: 方案3:把每一个串同一个位置的字符放在一起,用一个布尔数组记录与每一个小写字母的匹配关系,那么空间为26^15*len,爆内存: 方案4:把每一个串同一个位置