APIO2009 抢掠计划 Tarjan spfa/DAG-DP

题面

一道\(Tarjan\)缩点水题。因为可以反复经过节点,所以把一个联通快中的所有路口看做一个整体,缩点后直接跑\(spfa\)或者dp就好了。

在DAG上跑dp,复杂度\(O(n)\),而\(spfa\)为\(O(kn)\),所以还是优先选择dp(当然后面有\(spfa​\)的代码)

拓扑时搞DP,\(f[i]​\)表示在DAG上\(i​\)节点时,当前最大钱数,转移\(f[v]=max(f[v], f[u]+w[v])​\)

#include <cstdio>
#include <queue>
#define MAXN 500005
#define MIN(A,B) ((A)<(B)?(A):(B))
#define MAX(A,B) ((A)>(B)?(A):(B))
using namespace std;
int n,m,sta,p;
bool hav[MAXN],col_hav[MAXN];
int head[MAXN],nxt[MAXN],vv[MAXN],tot;
inline void add_edge(int u, int v){
vv[++tot]=v;
nxt[tot]=head[u];
head[u]=tot;
}
int s[MAXN],top;
bool ins[MAXN];
int col[MAXN],col_cnt;
int val[MAXN],col_val[MAXN];
int low[MAXN],dfn[MAXN],cnt;
void tarjan(int u){
dfn[u]=++cnt;
low[u]=cnt;
s[++top]=u;
ins[u]=1;
for(register int i=head[u];i;i=nxt[i]){
int v=vv[i];
if(dfn[v]==0){
tarjan(v);
low[u]=MIN(low[u], low[v]);
}else if(ins[v]){
low[u]=MIN(low[u], dfn[v]);
}
}
if(dfn[u]==low[u]){
col[u]=++col_cnt;
ins[u]=0;
col_val[col_cnt]=val[u];
while(s[top]!=u){
col[s[top]]=col_cnt;
ins[s[top]]=0;
col_val[col_cnt]+=val[s[top]];
top--;
}
top--;
}
}
int head2[MAXN],nxt2[MAXN],vv2[MAXN],tot2;
inline void add_edge2(int u, int v){
vv2[++tot2]=v;
nxt2[tot2]=head2[u];
head2[u]=tot2;
}
int rdu[MAXN];
inline void build(){
for(register int u=1;u<=n;++u)
if(dfn[u]!=0){
for(register int i=head[u];i;i=nxt[i]){
int v=vv[i];
if(col[u]==col[v]) continue;
rdu[col[v]]++;
add_edge2(col[u], col[v]);
}
}
}
queue <int> q;
int f[MAXN],ans=0;
void dp(){
q.push(col[sta]);f[col[sta]]=col_val[col[sta]];
while(!q.empty()){
int u=q.front();q.pop();
for(register int i=head2[u];i;i=nxt2[i]){
int v=vv2[i];
f[v]=MAX(f[v], f[u]+col_val[v]);
if((--rdu[v])==0) q.push(v);
}
}
for(register int i=1;i<=col_cnt;++i)
if(col_hav[i]) ans=MAX(f[i], ans);
}
int main()
{
scanf("%d %d", &n, &m);
while(m--){
int a,b;scanf("%d %d", &a, &b);
add_edge(a,b);
}
for(register int i=1;i<=n;++i) scanf("%d", &val[i]);
scanf("%d %d", &sta, &p);
while(p--){
int x;scanf("%d", &x);
hav[x]=1;
}
tarjan(sta);
for(register int i=1;i<=n;++i)
if(hav[i]) col_hav[col[i]]=1;
build();
dp();
printf("%d", ans);
return 0;
}

但是比赛时,拓扑dp写炸了,于是换成了\(spfa\),下面是\(spfa\)的写法:

#include <cstdio>
#include <cstring>
#include <queue>
#define MAXN 500005
#define MAXM 500005
#define MIN(A,B) ((A)<(B)?(A):(B))
#define MAX(A,B) ((A)>(B)?(A):(B))
using namespace std;
int n,m,val[MAXM],sta,p;
int head[MAXM],nxt[MAXM],vv[MAXM],tot;
inline void add_edge(int u, int v){
vv[++tot]=v;
nxt[tot]=head[u];
head[u]=tot;
}
int low[MAXN],dfn[MAXN],cnt;
int s[MAXN],top;
int col[MAXN],col_cnt;
long long col_val[MAXN];
bool ins[MAXN];
bool col_can[MAXN];
bool hav[MAXN];
bool col_hav[MAXN];
void tarjan(int u){
ins[u]=1;
dfn[u]=low[u]=++cnt;
s[++top]=u;
for(register int i=head[u];i;i=nxt[i]){
int v=vv[i];
if(dfn[v]==0){
tarjan(v);
low[u]=MIN(low[u], low[v]);
}else if(ins[v]){
low[u]=MIN(low[u], dfn[v]);
}
}
if(low[u]==dfn[u]){
ins[u]=0;
col[u]=++col_cnt;
col_val[col_cnt]=val[u];
if(hav[u]) col_hav[col_cnt]=1;
while(s[top]!=u){
col[s[top]]=col_cnt;
ins[s[top]]=0;
col_val[col_cnt]+=val[s[top]];
if(hav[s[top]]) col_hav[col_cnt]=1;
top--;
}
top--;
}
}
int du[MAXN];
int head2[MAXN],nxt2[MAXM],vv2[MAXM],tot2;
inline void add_edge2(int u, int v){
vv2[++tot2]=v;
nxt2[tot2]=head2[u];
head2[u]=tot2;
}
void build(){
for(register int u=1;u<=n;++u)
for(register int i=head[u];i;i=nxt[i]){
int v=vv[i];
if(col[u]==col[v]) continue;
add_edge2(col[u], col[v]);
du[col[v]]++;
}
}
queue <int> q;
long long f[MAXN];
long long ans;
bool inq[MAXN];
void spfa(){
f[col[sta]]=col_val[col[sta]];
q.push(col[sta]);
while(!q.empty()){
int u=q.front();q.pop();
inq[u]=0;
for(register int i=head2[u];i;i=nxt2[i]){
int v=vv2[i];
if(f[v]<f[u]+col_val[v]){
f[v]=f[u]+col_val[v];
if(!inq[v]) inq[v]=1,q.push(v);
}
}
}
for(register int i=1;i<=col_cnt;++i)
if(col_hav[i]) ans=MAX(ans, f[i]);
}
int main()
{
scanf("%d %d", &n, &m);
while(m--){
int a,b;scanf("%d %d", &a, &b);
add_edge(a,b);
}
for(register int i=1;i<=n;++i)
scanf("%d", &val[i]);
scanf("%d %d", &sta, &p);
while(p--){
int x;scanf("%d", &x);
hav[x]=1;
}
tarjan(sta);
build();
spfa();
printf("%lld", ans);
return 0;
}

APIO2009 抢掠计划 Tarjan DAG-DP的更多相关文章

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

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

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

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

  3. [APIO2009]抢掠计划 ($Tarjan$,最长路)

    题目链接 Solution 裸题诶... 直接 \(Tarjan\) 缩点+ \(SPFA\) 最长路即可. 不过在洛谷上莫名被卡... RE两个点... Code #include<bits/ ...

  4. [luogu3627 APIO2009] 抢掠计划 (tarjan缩点+spfa最长路)

    传送门 Description Input 第一行包含两个整数 N.M.N 表示路口的个数,M 表示道路条数.接下来 M 行,每行两个整数,这两个整数都在 1 到 N 之间,第 i+1 行的两个整数表 ...

  5. P3627 [APIO2009]抢掠计划

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

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

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

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

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

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

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

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

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

随机推荐

  1. asp.net core-11.WebHost的配置

    1.添加空的web网站 ,在目录下添加settings.json文件,在控制台上输出json的信息 public class Program { public static void Main(str ...

  2. awesome-javascript

    一系列令人敬畏的浏览器端JavaScript库,资源和闪亮的东西. 令人敬畏的JavaScript 包管理员 装载机 捆扎机 测试框架 QA工具 MVC框架和库 基于节点的CMS框架 模板引擎 文章/ ...

  3. (十四)角色管理(Ztree插件的基本使用)

    1. 建表 角色表 菜单表 角色-菜单(这个表中的role_id和menuu_id都不能被设置为主键,否则当插入一个新角色的时候,一个角色可能拥有多个菜单(role_id重复),一个菜单可能被多个角色 ...

  4. OutOfRangeError的解决办法

    自制TFRecord数据集,训练神经网络出现的一个问题,及解决办法.   错误现象: 数据训练完成后,测试数据集正确率时,运行mnist_test.py文件,出现错误代码 问题分析:显示需测试数据10 ...

  5. JVM学习笔记——字节码指令

    JVM学习笔记——字节码指令 字节码 0与 1是计算机仅能识别的信号,经过0和1的不同组合产生了数字之上的操作.另外,通过不同的组合亦产生了各种字符.同样,可以通过不同的组合产生不同的机器指令.在不同 ...

  6. MySql8.0 安装重要的两步。

    1.去官网下载mysql社区版 windows安装包. 2.在安装包 安装的过程中,有一步就是启动mysql 会失败: 然后修改服务后,再次回到安装界面点击:execute,就会成功了. 先去配置一下 ...

  7. Uploadify 之使用

    uploadify 3.2.1是 jQuery提供的一个上传插件,其参数详解见 http://www.cnblogs.com/yangy608/p/3915349.html 这里列举一个实际应用的例子 ...

  8. 运动的border,仿当当简易效果

    突然想到以前看到当当上有个效果,当鼠标移上去,图片边框是运动添加上的,还以为是css3或者是canvas做的呢,做完幽灵按钮后,才知道,so  easy,只不过是animate+position的杰作 ...

  9. java利用MultipartRequest的getFileName方法不能得到原文件名问题

    想利用MultipartRequest的getFileName方法来一次获取多个上传的文件名字时,得到的不是文件的名字,而是 input 的name属性 最后找到了答案,解决方法,参照http://s ...

  10. No valid host was found. There are not enough hosts available-----openstack建虚拟机直接报错

    目录 No valid host was found. There are not enough hosts available-----openstack建虚拟机直接报错 一.问题现象: 二.解决思 ...