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

描述

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

输入格式

第一行包含两个整数N、M。N表示食品商店的个数,M表示道路条数。接下来M行,每行两个整数,这两个整数都在1到N之间,第i+1行的两个整数表示第i条道 路的起点和终点的食品商店编号。接下来N行,每行一个整数,按顺序表示每个食品商店处的干食喜爱度。接下来一行包含两个整数S、P,S表示学校的编号,也就是出发地点。P表示板面馆数目。接下来的一行中有P个整数,表示P个卖板面的食品商店的编号。

输出格式

输出一个整数,表示到达板面馆之前能得到的最多的干食喜爱度。

测试样例1

输入

6 7 
1 2 
2 3 
3 5 
2 4 
4 1 
2 6 
6 5 
10 
12 

16 


1 4 
4 3 5 6

输出

47

备注

40%的数据n,m<=300   100%的数据n,m<=3000

思路:

1、分析路可以重复走,想到强连通分量,如果强连通分量里面有一个点被访问,那么整个强连通分量都要被访问,否则答案偏小,于是先tarjan再缩点

2、缩点之后,整个图由一个有向有环图变为一个有向无环图,于是spfa处理,然后就AC了(bzoj上的好像能卡掉,WYW用tarjan写信息传递好像被卡了)

代码:

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<algorithm>
#include<queue>
#include<stack>
#define maxn 3005
#define maxint ~0U>>1
using namespace std;
stack<int> sta;
vector<int> comp[maxn];
int incomp[maxn],instack[maxn],dfn[maxn],low[maxn];
int index,cnum;
int n,m,q,d[maxn],rice[maxn],noodle[maxn],v[maxn],s,p,ans;
vector<int> g[maxn],nowg[maxn];
int nowrice[maxn],nownoodle[maxn],nows;
void input(){
    cin>>n>>m;
    int u,v;
    for(int i = 1;i <= m;i++){
        scanf("%d%d",&u,&v);
        g[u].push_back(v);

    }
    for(int i = 1;i <= n;i++){
        scanf("%d",&rice[i]);
    }
    cin>>s>>p;
    int nnow;
    for(int i = 1;i <= p;i++){
        scanf("%d",&nnow);
        noodle[nnow] = 1;
    }
}
void tarjan(int u){
    instack[u] = 2;
    dfn[u] = low[u] = ++index;
    sta.push(u);
    for(int i = 0;i < g[u].size();i++){
        int j = g[u][i];
        if(!dfn[j]){
            tarjan(j);
            low[u] = min(low[u],low[j]);
        }else if(instack[j] == 2){
            low[u] = min(low[u],dfn[j]);
        }
    }
    if(dfn[u] == low[u]){
        ++cnum;
        while(!sta.empty()){
            int t = sta.top();
            sta.pop();
            instack[t] = 1;
            incomp[t] = cnum;
            comp[cnum].push_back(t);
            if(t == u){
                break;
            }
        }
    }
}
void work(){
    for(int i = 1;i <= n;i++){
        if(!dfn[i]) tarjan(i);
    }
    int u,v,newu,newv;
    for(int i = 1;i <= n;i++){
        u = i;
        newu = incomp[u];
        nowrice[newu] += rice[u];
        if(noodle[u]) nownoodle[newu] = 1;
        if(u == s) nows = newu;
        for(int j = 0;j < g[u].size();j++){
            v = g[u][j];
            newv = incomp[v];
            if(newu == newv) continue;
            nowg[newu].push_back(newv);
        }
    }
}
void spfa(){
    queue<int> q;
    d[nows] = nowrice[nows];
    v[nows] = 1;
    q.push(nows);
    int xx,dd,to,wei;
    while(!q.empty()){
        xx = q.front();
        dd = d[xx];
        q.pop();
        v[xx] = 0;
        if(nownoodle[xx]) ans = max(ans,dd);
        for(int i = 0;i < nowg[xx].size();i++){
            to = nowg[xx][i];
            wei = nowrice[to];
            if(dd + wei > d[to]){
                d[to] = dd + wei;
                if(!v[to]){
                    v[to] = 1;
                    q.push(to);
                }
            }
        }
    }
    cout<<ans;
}
int main(){
    input();
    work();
    spfa();
    return 0;
}
时间: 2024-10-11 12:14:19

Tyvj1139 向远方奔跑(APIO 2009 抢掠计划)的相关文章

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

【BZOJ 1177】【APIO 2009】Oil

http://www.lydsy.com/JudgeOnline/problem.php?id=1177 前缀和优化,时间复杂度$O(nm)$ 因为数据不全,快速读入会导致RE,切记! #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N = 1503; int in() { int k = 0, fh = 1; char c = getchar()

【p3627】[APIO2009] 抢掠计划

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

[APIO2009]抢掠计划

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

[BZOJ 1179][APIO 2009]Atm

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

【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

BZOJ1179_APIO2009_抢掠计划_C++

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

BZOJ 1179 APIO 2009 Atm Tarjan+SPFA

题目大意:给出一张有向图,每一个节点有一个权值,经过一次之后会取走节点上的权值.有一个原点,多个汇点,问最多能收获多少权值. 思路:做一次Tarjan将图变成拓扑图,然后直接跑SPFA+Heap,比较慢,但是用了高大上的namespace,很开心. CODE: #include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm>

洛谷3627 [APIO2009]抢掠计划

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