先来看一下题目描述:

题目描述

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

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

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

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

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

输入输出格式

输入格式:

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

输出格式:

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

好了,以上是题目描述qwq。

那么现在我们考虑一下用什么方法来做这道题。

首先我们明确一点:这是一个有向有环图。所以我们就应该考虑Tarjan之类的用以处理有向图的方法了。

按照最初的印象,我们好像应该是要跑一次最长路,SPFA完全可以做到这一点。但是我们要知道,他有两个特殊条件:

  1.没有边权,只有点权,也没有消耗。并且我们是要从这个图里面获得最大的点权,也就是说:边可以走好多次,但是点走一次之后就变为了0。

  2.我们最后要回到某一个指定的位置。所以SPFA就十分方便。

所以在经过反复思考后,我们决定用Tarjan解决这个问题。那么为什么呢?

因为Tarjan可以很好地解决关于图的连通性的问题。 由此,我们就可以把一个环缩成一个点。

因为我们知道,一旦我们进入了一个环,由于不计费用,所以我们最佳的方案就是直接跑完这个环。就像样例中的1,2,4一样。

好了接下来讲一下如何实现。

1.首先用Tarjan将所有的环所称一个点。

2.跑一边最长路SPFA。

(好像根本没有什么总结的必要emmmm......)

那么接下来是各段的代码。

#define MAXN 100010
int Yeasion[MAXN];//DFS时搜索的顺序。
int Nein[MAXN];//Nein[i]就是表示在当前i节点能够回到的最大的节点处。
bool flag[MAXN];//是否在栈里面
int belong[MAXN];//表示i节点在Tarjan之后属于什么节点。
int value[MAXN];//表示Tarjan之前的节点的价值
int behind_value[MAXN];//表示Tarjan之后的节点价值
int stack[MAXN],cnt,top,ken;//......
vector<int> line[MAXN];//使用不定长数组代替前向星,好像会简洁一点emmmm.....
void Tarjan(int now)
{
    //一下是固定不变的Tarjan  qwq
    Nein[now]=Yeasion[now]=++ken;
    stack[++top]=now;
    flag[now]=true;
    ;i<line[now].size();i++)
    {
        int next=line[now][i];
        if(!Yeasion[next])
        {
            Tarjan(next);
            if(Nein[next]<Nein[now])
                Nein[now]=Nein[next];
        }
        else
            if(flag[next])
            Nein[now]=min(Yeasion[next],Nein[now]);
    }
    if(Nein[now]==Yeasion[now])
    {
        cnt++;//这里我们在Tarjan之后新建了一个图,然后我们资金编造了一个顺序。
        int pass;//顾名思义,过去的节点嘛...
        do
        {
            pass=stack[top--];//更新pass,进行退栈操作。
            belong[pass]=cnt;//表明原图中的pass点属于新图中的cnt节点。
            behind_value[cnt]+=value[pass];//更新新图中的cnt的节点大小
            flag[pass]=false;//退栈.....
        }while(pass!=now);
    }
    return ;
}

然后我们跑一边SPFA就可以了。下面上全部代码。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#define MAXN 100001
using namespace std;

int n,m,s,p;

//SPFA用
];
queue<int>q;
];

//Tarjan用
int Yeasion[MAXN];//DFS时搜索的顺序。
int Nein[MAXN];//Nein[i]就是表示在当前i节点能够回到的最大的节点处。
bool flag[MAXN];//是否在栈里面
int belong[MAXN];//表示i节点在Tarjan之后属于什么节点。
int value[MAXN];//表示Tarjan之前的节点的价值
int behind_value[MAXN];//表示Tarjan之后的节点价值
int stack[MAXN],cnt,top,ken;//......
vector<int> line[MAXN];//使用不定长数组代替前向星,好像会简洁一点emmmm.....
vector<];
];
void Tarjan(int now)
{
    //一下是固定不变的Tarjan  qwq
    Nein[now]=Yeasion[now]=++ken;
    stack[++top]=now;
    flag[now]=true;
    ;i<line[now].size();i++)
    {
        int next=line[now][i];
        if(!Yeasion[next])
        {
            Tarjan(next);
            if(Nein[next]<Nein[now])
                Nein[now]=Nein[next];
        }
        else
            if(flag[next])
            Nein[now]=min(Yeasion[next],Nein[now]);
    }
    if(Nein[now]==Yeasion[now])
    {
        cnt++;//这里我们在Tarjan之后新建了一个图,然后我们资金编造了一个顺序。
        int pass;//顾名思义,过去的节点嘛...
        do
        {
            pass=stack[top--];//更新pass,进行退栈操作。
            belong[pass]=cnt;//表明原图中的pass点属于新图中的cnt节点。
            behind_value[cnt]+=value[pass];//更新新图中的cnt的节点大小
            flag[pass]=false;//退栈.....
        }while(pass!=now);
    }
    return ;
}
void link()//建新图
{
     ;i<=n;i++)
        ;j<line[i].size();j++)
        {
            int next=line[i][j];
            if(belong[i]!=belong[next])
            {
                tline[belong[i]].push_back(belong[next]);
                ind[belong[next]]+=;
            }
        }
}
void SPFA()
{
    while(!q.empty())
    {
        int pas=q.front();
        q.pop();
        inque[pas]=false;
        ;i<tline[pas].size();i++)
        {
            int next=tline[pas][i];
            if(dist[next]>dist[pas]-behind_value[next])
            {
                dist[next]=dist[pas]-behind_value[next];
                if(!inque[next])
                {
                    inque[next]=true;
                    q.push(next);
                }
            }
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    int a,b;
    ;i<=m;i++)
    {
        scanf("%d%d",&a,&b);
        line[a].push_back(b);
    }
    ;i<=n;i++)
        scanf("%d",&value[i]);
    ;i<=n;i++)
        if(!belong[i])
            Tarjan(i);
    scanf("%d%d",&s,&p);
    memset(dist,,sizeof(dist));
    dist[belong[s]]=-behind_value[belong[s]];
    q.push(belong[s]);
    inque[belong[s]]=true;
    ;
    ;i<=p;i++)
    {
        scanf("%d",&a);
        ans=min(ans,dist[belong[a]]);
    }
    printf("%d",-ans);
}

[luoguP3627][APIO2009]抢掠计划的更多相关文章

  1. P3627 [APIO2009]抢掠计划

    P3627 [APIO2009]抢掠计划 Tarjan缩点+最短(最长)路 显然的缩点...... 在缩点时,顺便维护每个强连通分量的总权值 缩完点按照惯例建个新图 然后跑一遍spfa最长路,枚举每个 ...

  2. APIO2009 抢掠计划 Tarjan DAG-DP

    APIO2009 抢掠计划 Tarjan spfa/DAG-DP 题面 一道\(Tarjan\)缩点水题.因为可以反复经过节点,所以把一个联通快中的所有路口看做一个整体,缩点后直接跑\(spfa\)或 ...

  3. 题解 P3627 【[APIO2009]抢掠计划】

    咕了四个小时整整一晚上 P3627 [APIO2009] 抢掠计划(https://www.luogu.org/problemnew/show/P3627) 不难看出答案即为该有向图的最长链长度(允许 ...

  4. [APIO2009]抢掠计划(Tarjan,SPFA)

    [APIO2009]抢掠计划 题目描述 Siruseri 城中的道路都是单向的.不同的道路由路口连接.按照法律的规定, 在每个路口都设立了一个 Siruseri 银行的 ATM 取款机.令人奇怪的是, ...

  5. 【洛谷P3627】[APIO2009]抢掠计划

    抢掠计划 题目链接 比较水的缩点模板题,Tarjan缩点,重新建图,记录联通块的钱数.是否有酒吧 DAG上记忆化搜索即可 #include<iostream> #include<cs ...

  6. [APIO2009]抢掠计划

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

  7. [APIO2009]抢掠计划 tarjan缩点+spfa BZOJ1179

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

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

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

  9. 洛谷 P3627 [APIO2009]抢掠计划 Tarjan缩点+Spfa求最长路

    题目地址:https://www.luogu.com.cn/problem/P3627 第一次寒假训练的结测题,思路本身不难,但对于我这个码力蒟蒻来说实现难度不小-考试时肛了将近两个半小时才刚肛出来. ...

随机推荐

  1. linux安装PHP加速器eAccelerator

    感慨下:做前端开发不少日子了,在前公司也使用过一段时间linux系统,对apache配置比较熟悉,可是对nginx配置还是不熟悉,毕竟自己是做前端开发的,大后端的事情还是比较排斥,以后多练习.前些日子 ...

  2. React.js 小书 Lesson9 - 事件监听

    作者:胡子大哈 原文链接:http://huziketang.com/books/react/lesson9 转载请注明出处,保留原文链接和作者信息. 在 React.js 里面监听事件是很容易的事情 ...

  3. Eclipse error: “The import XXX cannot be resolved”

    解决 Eclipse error: “The import XXX cannot be resolved” eclipse中修改: 1. 项目-->Properties-->java bu ...

  4. 【Ubuntu】设置静态ip地址

    一.Ubuntu16.04设置静态IP1.获取网卡的名字   ip route show 2.获取网卡的名字 vim /etc/network/interfaces auto ens33 iface ...

  5. [转]Asp.net Core 使用Redis存储Session

    本文转自:http://www.cnblogs.com/hantianwei/p/5723959.html 前言 Asp.net Core 改变了之前的封闭,现在开源且开放,下面我们来用Redis存储 ...

  6. C#动态方法调用 提高程序的扩展性

    此篇将介绍C#如何在运行时动态调用方法.当某些类型是运行时动态确定时,编译时的静态编码是无法解决这些动态对象或类的方法调用的.此篇则给你一把利剑,让动态对象的方法调用成为可能. 1.动态调用dll里的 ...

  7. 关于两个 IQueryable 合并

    原先根据需求要对数据进行两种筛选,起初写过滤条件,但是过滤后发现有的数据重叠.因此改为查询两次. 因为查询后返回的是两个相同的.匿名的 IQueryable ,最终的目的是想两个 类型结合成一个. 参 ...

  8. WPF的依赖项属性

    WPF的依赖项属性 属性与事件是.NET抽象模型的核心部分.WPF使用了更高级的依赖项属性(Dependency Property)功能来替换原来.NET的属性,实现了更高效率的保存机制,还添加了附加 ...

  9. java程序: 从kernel.ubuntu.com下载kernel - HttpURLConnection

    用java实现从kernel.ubuntu.com下载内核的小工具 现在的最新的LTS版本是4.19,目前已经更新到4.19.13了. Kernel的更新通知里,经常有下面的陈述: 作为一个听劝的人, ...

  10. Thrift笔记(二)--Thrift框架分层设计

    thrift架构设计使用了分层设计,类似TCP/IP分层,上次使用下层提供的服务.分层设计在计算机中是一个常用的设计,上层和下层定义好接口或者说协议,下层实现可以随意更换,只要实现好定义的接口和协议就 ...