【p3627】[APIO2009] 抢掠计划

Description

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

Banditji 计划实施 Siruseri 有史以来最惊天动地的 ATM 抢劫。他将从市中心 出发,沿着单向道路行驶,抢劫所有他途径的 ATM 机,最终他将在一个酒吧庆 祝他的胜利。

使用高超的黑客技术,他获知了每个 ATM 机中可以掠取的现金数额。他希 望你帮助他计算从市中心出发最后到达某个酒吧时最多能抢劫的现金总数。他可 以经过同一路口或道路任意多次。但只要他抢劫过某个 ATM 机后,该 ATM 机 里面就不会再有钱了。 例如,假设该城中有 6 个路口,道路的连接情况如下图所示:

市中心在路口 1,由一个入口符号→来标识,那些有酒吧的路口用双圈来表

示。每个 ATM 机中可取的钱数标在了路口的上方。在这个例子中,Banditji 能抢 劫的现金总数为 47,实施的抢劫路线是:1-2-4-1-2-3-5。

Input

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

Output

输出一个整数,表示 Banditji 从市中心开始到某个酒吧结束所能抢劫的最多 的现金总数。

\(Tarjan\)缩点跑最长路,

在求强联通分量的时候维护每个联通分量的\(val\)(即当前强联通分量中所有\(atm\)的钱数.

不能再次建边的时候再求.(会出锅,但是原理我不太知道。

再对强联通分量建边跑最长路即可.

注意:\(Dijkstra\)的贪心策略不可跑最长路。

这里数组可以重复使用,不过这题没有卡数组,就没有重复使用了 qwq.

代码

#include<cstdio>
#include<cctype>
#include<queue>
#define N 500008
#define R register
using namespace std;
inline void in(int &x)
{
    int f=1;x=0;char s=getchar();
    while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
    while(isdigit(s)){x=x*10+s-'0';s=getchar();}
    x*=f;
}
int n,m,head[N],tot,low[N],dfn[N],col,belong[N],idx,stk[N],pos;
int val[N],v[N],h[N],ttt,p,t[N],dis[N],top,s,ans;
struct cod{int u,v;}edge[N<<2],e[N<<2];
bool inq[N],vis[N];
inline void add(int x,int y)
{
    edge[++tot].u=head[x];
    edge[tot].v=y;
    head[x]=tot;
}
inline void ado(int x,int y)
{
    e[++ttt].u=h[x];
    e[ttt].v=y;
    h[x]=ttt;
}
inline void spfa(int s)
{
    for(R int i=1;i<=col;i++)dis[i]=-214748364;
    queue<int>q;
    q.push(s);vis[s]=true;dis[s]=val[s];
    while(!q.empty())
    {
        int u=q.front();q.pop();vis[u]=false;
        for(R int i=h[u];i;i=e[i].u)
        {
            if(dis[e[i].v]<dis[u]+val[e[i].v])
            {
                dis[e[i].v]=dis[u]+val[e[i].v];
                if(!vis[e[i].v])
                {
                    vis[e[i].v]=true;
                    q.push(e[i].v);
                }
            }
        }
    }
    for(R int i=1;i<=p;i++)
        ans=max(ans,dis[belong[t[i]]]);
    printf("%d",ans);
}
void tarjan(int x)
{
    dfn[x]=low[x]=++idx;
    stk[++top]=x;inq[x]=true;
    for(R int i=head[x];i;i=edge[i].u)
    {
        if(!dfn[edge[i].v])
        {
            tarjan(edge[i].v);
            low[x]=min(low[x],low[edge[i].v]);
        }
        else if(inq[edge[i].v])
            low[x]=min(low[x],dfn[edge[i].v]);
    }
    if(low[x]==dfn[x])
    {
        col++;
        int now=-1;
        while(now!=x)
        {
            now=stk[top--];
            inq[now]=false;
            belong[now]=col;
            val[col]+=v[now];
        }
    }
}
int main()
{
    in(n),in(m);
    for(R int i=1,x,y;i<=m;i++)
    {
        in(x),in(y);
        add(x,y);
    }
    for(R int i=1;i<=n;i++)in(v[i]);
    for(R int i=1;i<=n;i++)
        if(!dfn[i])tarjan(i);
    for(R int i=1;i<=n;i++)
        for(R int j=head[i];j;j=edge[j].u)
            if(belong[edge[j].v]!=belong[i])
                ado(belong[i],belong[edge[j].v]);
    in(s);in(p);
    for(R int i=1;i<=p;i++)in(t[i]);
    spfa(belong[s]);
}

原文地址:https://www.cnblogs.com/-guz/p/9780291.html

时间: 2024-10-11 12:14:27

【p3627】[APIO2009] 抢掠计划的相关文章

APIO2009 抢掠计划 Tarjan DAG-DP

APIO2009 抢掠计划 Tarjan DAG-DP 题面 一道\(Tarjan\)缩点水题.因为可以反复经过节点,所以把一个联通快中的所有路口看做一个整体,缩点后直接跑spfa或者dp就好了. 我选择了在DAG上跑dp,毕竟复杂度\(O(n)\) 拓扑时搞DP,\(f[i]\)表示在DAG上\(i\)节点时,当前最大钱数,转移\(f[v]=max(f[v], f[u]+w[v])?\) #include <cstdio> #include <queue> #define MAX

[APIO2009]抢掠计划

题目描述 Siruseri 城中的道路都是单向的.不同的道路由路口连接.按照法律的规定, 在每个路口都设立了一个 Siruseri 银行的 ATM 取款机.令人奇怪的是,Siruseri 的酒吧也都设在路口,虽然并不是每个路口都设有酒吧. Banditji 计划实施 Siruseri 有史以来最惊天动地的 ATM 抢劫.他将从市中心 出发,沿着单向道路行驶,抢劫所有他途径的 ATM 机,最终他将在一个酒吧庆 祝他的胜利. 使用高超的黑客技术,他获知了每个 ATM 机中可以掠取的现金数额.他希 望

【bzoj1179】[Apio2009]抢掠计划atm 强连通分量缩点+spfa

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

洛谷3627 [APIO2009]抢掠计划

题目描述 输入格式: 第一行包含两个整数 N.M.N 表示路口的个数,M 表示道路条数.接下来 M 行,每行两个整数,这两个整数都在 1 到 N 之间,第 i+1 行的两个整数表示第 i 条道路的起点和终点的路口编号.接下来 N 行,每行一个整数,按顺序表示每 个路口处的 ATM 机中的钱数.接下来一行包含两个整数 S.P,S 表示市中心的 编号,也就是出发的路口.P 表示酒吧数目.接下来的一行中有 P 个整数,表示 P 个有酒吧的路口的编号. 输出格式: 输出一个整数,表示 Banditji

Tyvj1139 向远方奔跑(APIO 2009 抢掠计划)

描述 在唐山一中,吃饭是一件很令人头疼的事情,因为你不可能每次都站在队伍前面买饭,所以,你最需要做的一件事就是——跑饭.而跑饭的道路是无比艰难的,因为路是单向的(你要非说成是双向的我也没法,前提是你可以逆着2000+个狂热的跑饭群众而行),所以要合理选择路线.并且,在抵达你的目的地——板面馆之前,你需要先买一些干粮,比如烧饼之类的.现在给你每个干食商店的位置和干食喜爱度,请你设计一个跑饭方案使得在到达板面馆之前能得到尽可能多的干食喜爱度. 输入格式 第一行包含两个整数N.M.N表示食品商店的个数

BZOJ1179_APIO2009_抢掠计划_C++

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1179 一道用 Tarjan 缩点+SPFA 最长路的题(Tarjan 算法:http://www.cnblogs.com/hadilo/p/5889333.html ) 我们可以这样考虑,把一个连通块缩成一个点,点权为所有权值和,且只要一个点有酒吧那么该点也就有酒吧 因为当我们进入该连通块任意一个点时,显然把它里面所有的点都抢一遍才使答案最优,而且能回到原进入点,并且只要有一个有酒吧就可以选

APIO2009劫掠计划

/* 缩点加上最长路 应该用拓扑序列的 不想写 spfa跑一下吧 */ #include<cstdio> #include<algorithm> #include<cstring> #include<queue> #include<iostream> #define M 500200 #define ll long long using namespace std; int be[M], ed[M], to[M], nxt[M], dft, he

[APIO2009-C]抢掠计划

题:https://www.cometoj.com/problem/0461 分析:求边双,最后求多汇点最长路 #include<iostream> #include<cstring> #include<algorithm> #include<cstdio> #include<vector> #include<queue> #define pb push_back using namespace std; const int M=5e

抢掠计划

https://loj.ac/problem/10096 题目描述 某人准备从1号节点出发开始抢劫,并在一个有酒吧的节点停止抢劫,已知每个节点ATM机拥有的钱数,求最多抢劫的钱数(可重复经过道路,抢完后ATM机没钱). 思路 我们考虑对于一个强连通分量,他必定可以抢完这个强连通分量中所有的钱并到达任意节点,因此我们可以缩点.缩点之后每个点的点权即为这个强连通分量的总金额.我们对于缩点后的DAG,显然可以将点权转化为边权,在这张图上找最长路.这里最长路我们可以用spfa实现,这里我们避免用拓扑,因