BZOJ1179_APIO2009_抢掠计划_C++

  题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1179

  一道用 Tarjan 缩点+SPFA 最长路的题(Tarjan 算法:http://www.cnblogs.com/hadilo/p/5889333.html )

  我们可以这样考虑,把一个连通块缩成一个点,点权为所有权值和,且只要一个点有酒吧那么该点也就有酒吧

  因为当我们进入该连通块任意一个点时,显然把它里面所有的点都抢一遍才使答案最优,而且能回到原进入点,并且只要有一个有酒吧就可以选择在那里庆祝

  缩完点后,就可以用 SPFA 求最长路,边权变为点权,因为里面已经没有环了,所以可以用

  当然最大路也可以用 Dijkstra 或 DP 等方法做

  还有这道题细节很多很多,调了我4个多小时QuQ

 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstdlib>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<cmath>
 7 #include<queue>
 8 #include<stack>
 9 #define N 500001
10 using namespace std;
11
12 int t,first[N],next[N],back[N],last[N],v[N],a[N],dfn[N],low[N],ans,d[N];
13 bool f[N],g[N],b[N];
14 stack<int> s;
15 queue<int> q;
16 void tarjan(int x)
17 {
18     dfn[x]=low[x]=++t;
19     s.push(x);
20     int i;
21     for (i=first[x];i;i=next[i])
22         {
23             if (f[v[i]]) continue;
24             if (dfn[v[i]]) low[x]=min(low[x],dfn[v[i]]);
25             else
26                 {
27                     tarjan(v[i]);
28                     low[x]=min(low[x],low[v[i]]);
29                 }
30         }
31     if (dfn[x]==low[x])
32         {
33             int k,c=first[x];
34             while (s.top()!=x)
35                 {
36                     i=c;
37                     k=s.top();
38                     f[k]=b[k]=1;
39                     s.pop();
40                     a[x]+=a[k];
41                     g[x]|=g[k];
42                     while (next[i]) i=next[i];
43                     next[i]=first[k];
44                     c=i;
45                     for (i=last[k];i;i=back[i]) v[i]=x;
46                 }
47             f[s.top()]=1;
48             s.pop();
49         }
50 }
51 int main()
52 {
53     int n,m,i,x,k;
54     scanf("%d%d",&n,&m);
55     for (i=1;i<=m;i++)
56         {
57             scanf("%d%d",&x,&v[i]);
58             next[i]=first[x];
59             first[x]=i;
60             back[i]=last[v[i]];
61             last[v[i]]=i;
62         }
63     for (i=1;i<=n;i++)
64         {
65             scanf("%d",&a[i]);
66             g[i]=b[i]=f[i]=0;
67         }
68     scanf("%d%d",&k,&m);
69     for (i=1;i<=m;i++)
70         {
71             scanf("%d",&x);
72             g[x]=1;
73         }
74     tarjan(k);
75     for (i=1;i<=n;i++) f[i]=1;
76     d[k]=a[k];
77     q.push(k);
78     while (!q.empty())
79         {
80             k=q.front();
81             q.pop();
82             if (g[k]) ans=max(ans,d[k]);
83             for (i=first[k];i;i=next[i])
84                 {
85                     if (b[v[i]]||v[i]==k) continue;
86                     if (d[v[i]]<d[k]+a[v[i]])
87                         {
88                             d[v[i]]=d[k]+a[v[i]];
89                             q.push(v[i]);
90                         }
91                 }
92         }
93     cout<<ans<<endl;
94     return 0;
95 }

  这道题需要开无限栈,因为递归的 Tarjan 会爆栈,然而并不会手写栈

  BZOJ 上幸好开了无限栈,不然就 RE 了,不过其它的 OJ 好像没有开无限栈,RE 两个点……

  只好去网上下了一个代码,在 CodeVS 上交了一发手写栈的 Tarjan,终于A了orz(手写栈的戳这里: http://www.cnblogs.com/hadilo/p/5892791.html )

版权所有,转载请联系作者,违者必究

QQ:740929894

时间: 2024-08-29 05:57:58

BZOJ1179_APIO2009_抢掠计划_C++的相关文章

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

【p3627】[APIO2009] 抢掠计划

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

[APIO2009]抢掠计划

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

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

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

【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

[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实现,这里我们避免用拓扑,因

[知识点]Tarjan算法

// 此博文为迁移而来,写于2015年4月14日,不代表本人现在的观点与看法.原始地址:http://blog.sina.com.cn/s/blog_6022c4720102vxnx.html 1.前言 我始终记得去年冬天有天吃完饭后,我们在买东西的时候讨论着强连通分量和Tarjan什么的.当时我真的什么都没听懂啊...什么强连通图,强连通分量,极大强连通分量...当然现在还是知道了. 2.概念 Tarjan算法,由Tarjan发明.作用在于求图中的强连通分量.什么是强连通?在有向图G中,如果两