P3119 [USACO15JAN]Grass Cownoisseur G

tarjan缩点+分层图上跑 spfa最长路

约翰有 \(n\) 块草场,编号 \(1\) 到 \(n\),这些草场由若干条单行道相连。奶牛贝西是美味牧草的鉴赏家,她想到达尽可能多的草场去品尝牧草。

贝西总是从 \(1\) 号草场出发,最后回到 \(1\) 号草场。她想经过尽可能多的草场,贝西在通一个草场只吃一次草,所以一个草场可以经过多次。

因为草场是单行道连接,这给贝西的品鉴工作带来了很大的不便,贝西想偷偷逆向行走一次,但最多只能有一次逆行。

问,贝西最多能吃到多少个草场的牧草。


 

#include<cstdio>
#include<utility>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<map>
#include<iomanip>
#include<queue>
#include<cstring>
#define reg register
#define EN std::puts("")
#define LL long long
inline int read(){
register int x=0;register int y=1;
register char c=std::getchar();
while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
return y?x:-x;
}
//P3119 [USACO15JAN]Grass Cownoisseur G
//https://www.luogu.com.cn/problem/P3119
//分层图 +tarjan+spfa 最长路
//分层图,第一层是( 1~n )没用过逆着走的机会的,第二层( n+1~2*n )是用过的,两层之间连反向边
//不过要缩点以后再分层,不然缩点的时候就是分层的可能就缩乱了
//一开始直接连玩分层图再跑最长路,那样似乎并不行 //然而,这样分层跑最长路的时候,并不会出现重复计算的情况
//下面讨论的 u,v,w 等,都是指的缩完点后的一个强连通分量,而不是单纯的一个点
//说的 1,其实也是指的 1 所在的强连通分量,只不过这样描述起来更简便而已 //比如我从 u 走到了 v,然后从 v 通过一个反向边回到了它的上一个节点,设其为 w
//然后再通过 w 走回了 u
//那么,u->v,w->v,w->u,这样就会让 u 多算一遍
//如果 u 就是 1,没有影响,因为我门一开始初始化 dis[1]=0,这样回到 1 的时候再算一遍是没错的
//如果 u 不是 1,一定是 1 通过一系列路径,走到了 u,然后用了一次逆着走的机会,又回到了 u,对 u 计算了两遍
//但这样的话,就不会再回到 1 了,因为不能再逆着走了
//如果 u 通过一些路径回到 u 的话,1 能到 u,u 也能回 1,那 1 和 u 就是一个强连通分量了,不成立
//那么既然多算了一遍 u,就不能回到 1 了,肯定也不会对答案产生影响了 //只有一个强连通分量的情况要特判
#define N 200006
#define M 300006
int fir[N],nex[M],to[M],tot;
int fir_[N],nex_[M],to_[M],tot_;
int dfn[N],low[N],dfscnt;
int scc[N],scccnt,indeg[N],size[N];
int stack[N],top;
int n,m;
int dis[N];
inline void add(int u,int v){
to[++tot]=v;
nex[tot]=fir[u];fir[u]=tot;
}
inline void add_(int u,int v){
to_[++tot_]=v;
nex_[tot_]=fir_[u];fir_[u]=tot_;
}
void tarjan(int u){
stack[top++]=u;low[u]=dfn[u]=++dfscnt;
for(reg int v,i=fir[u];i;i=nex[i]){
v=to[i];
if(!dfn[v]){
tarjan(v);
low[u]=std::min(low[u],low[v]);
}
else if(!scc[v]) low[u]=std::min(low[u],dfn[v]);
}
if(dfn[u]==low[u]){
scccnt++;
do{
scc[stack[--top]]=scccnt;size[scccnt]++;
}while(stack[top]!=u);
}
}
inline void rebuild(){
for(reg int i=1;i<=n;i++){
for(reg int j=fir[i];j;j=nex[j])if(scc[i]!=scc[to[j]]){
add_(scc[i],scc[to[j]]);
add_(scc[i]+scccnt,scc[to[j]]+scccnt);
add_(scc[to[j]],scc[i]+scccnt);
}
}
for(reg int i=1;i<=scccnt;i++) size[i+scccnt]=size[i];
}
std::queue<int>q;
int vis[N];
inline void spfa(){
vis[scc[1]]=1;q.push(scc[1]);
while(!q.empty()){
reg int u=q.front(),v;q.pop();vis[u]=0;
for(reg int i=fir_[u];i;i=nex_[i]){
v=to_[i];
if(dis[v]<dis[u]+size[u]){
dis[v]=dis[u]+size[u];
if(!vis[v]) q.push(v),vis[v]=1;
}
}
}
}
int main(){
n=read();m=read();
for(reg int u,v,i=1;i<=m;i++){
u=read();v=read();
add(u,v);
}
for(reg int i=1;i<=n;i++)if(!dfn[i]) tarjan(i);
if(scccnt==1) return std::printf("%d",n),0;
rebuild();
spfa();
std::printf("%d",dis[scc[1]+scccnt]);
// EN;EN;
// for(reg int i=1;i<=n;i++) std::printf("%d ",scc[i]);EN;
// for(reg int i=1;i<=scccnt;i++) std::printf("%d ",size[i]);EN;
return 0;
}

P3119 [USACO15JAN]Grass Cownoisseur G的更多相关文章

  1. 【题解】洛谷P3119 Grass Cownoisseur G

    题面:洛谷P3119 Grass Cownoisseur G 本人最近在熟悉Tarjan的题,刷了几道蓝题后,我飘了 趾高气扬地点开这道紫题,我一瞅: 哎呦!这不是分层图吗? 突然就更飘了~~~ 用时 ...

  2. [USACO15JAN]Grass Cownoisseur

    \(tarjan\)缩点+\(DAG\)上最长路. 求一个以\(1\)为起点的最长路和一个以\(1\)为终点的最长路,然后找那个逆行边就行了. 然后这个我\(RE\)了好久,原因是\(vector\) ...

  3. 解题:USACO15JAN Grass Cownoisseur

    解题 首先缩点没啥可说的,然后考虑枚举这次逆行的边.具体来说在正常的图和反图上各跑一次最长路,然后注意减掉起点的贡献,用拓扑排序实现(我这里瞎写了个Bellman_Ford,其实在DAG上这好像和拓扑 ...

  4. 洛谷 P3119 [USACO15JAN]草鉴定Grass Cownoisseur (SCC缩点,SPFA最长路,枚举反边)

    P3119 [USACO15JAN]草鉴定Grass Cownoisseur 题目描述 In an effort to better manage the grazing patterns of hi ...

  5. 洛谷 P3119 [USACO15JAN]草鉴定Grass Cownoisseur 解题报告

    P3119 [USACO15JAN]草鉴定Grass Cownoisseur 题目描述 约翰有\(n\)块草场,编号1到\(n\),这些草场由若干条单行道相连.奶牛贝西是美味牧草的鉴赏家,她想到达尽可 ...

  6. 洛谷——P3119 [USACO15JAN]草鉴定Grass Cownoisseur

    P3119 [USACO15JAN]草鉴定Grass Cownoisseur 题目描述 In an effort to better manage the grazing patterns of hi ...

  7. 【洛谷P3119】[USACO15JAN]草鉴定Grass Cownoisseur

    草鉴定Grass Cownoisseur 题目链接 约翰有n块草场,编号1到n,这些草场由若干条单行道相连.奶牛贝西是美味牧草的鉴赏家,她想到达尽可能多的草场去品尝牧草. 贝西总是从1号草场出发,最后 ...

  8. [USACO15JAN]草鉴定Grass Cownoisseur(分层图+tarjan)

    [USACO15JAN]草鉴定Grass Cownoisseur 题目描述 In an effort to better manage the grazing patterns of his cows ...

  9. bzoj3887: [Usaco2015 Jan]Grass Cownoisseur

    题意: 给一个有向图,然后选一条路径起点终点都为1的路径出来,有一次机会可以沿某条边逆方向走,问最多有多少个点可以被经过?(一个点在路径中无论出现多少正整数次对答案的贡献均为1) =>有向图我们 ...

随机推荐

  1. Java中的垃圾回收算法详解

    一.前言   前段时间大致看了一下<深入理解Java虚拟机>这本书,对相关的基础知识有了一定的了解,准备写一写JVM的系列博客,这是第二篇.这篇博客就来谈一谈JVM中使用到的垃圾回收算法. ...

  2. 实战if-else 过多详解

    1.本文实例代码仅仅是俩个小例子. package com.example.demo.pattern.ifElse; import java.util.HashMap; import java.uti ...

  3. 使用spring连接mysql数据库出错

    最近在学习spring框架,但是在学到JdbcTemplate时连接数据库一直报错,百度谷歌各种查找都能没有解决问题,简直要癫狂,报错信息如下: org.springframework.jdbc.Ca ...

  4. 漏洞复现环境集锦-Vulhub

    0x01 Vulhub简介 Vulhub是一个面向大众的开源漏洞靶场,无需docker知识,简单执行两条命令即可编译.运行一个完整的漏洞靶场镜像. 0x02 安装 # 安装pip curl -s ht ...

  5. AJ整理问题之:内存堆栈

    内存 数据在内存中的存放 在计算机中,运行的应用程序的数据都是保存在内存中的. 不同类型的数据,保存的内存区域不同,其中包括: 1:栈区(stack)由编译器自动分配并释放,一半存放函数的参数值,局部 ...

  6. 第三章:shell变量知识进阶

    特殊变量:位置变量大于9的时候,需要加上(),例如$(10)$*获取脚本的所有参数,如果不加""和$@是一样的效果,如果加上"",则表示所有参数组成一个字符串$ ...

  7. 时间格式的转化 vue与js 年月日 时分秒

    首先使用原生转化的方法 第一种 //时间转换 dateStr(d, sign) { //如果没有传递符号,给一个默认的符号 if (!sign) { sign = '-' } //获取d里面年月日时分 ...

  8. 阿里Canal框架数据库同步-实战教程

    一.Canal简介: canal是阿里巴巴旗下的一款开源项目,纯Java开发.基于数据库增量日志解析,提供增量数据订阅&消费,目前主要支持了MySQL(也支持mariaDB). 二.背景介绍: ...

  9. php+mysql数据库联合查询 left join 右侧数据重复问题

    情况:多表联合查询(三表及以上联合查询) 分析: A left join B left join C left join D 假如: 表B.C.D都与表A关联查询 A left join B 4条数据 ...

  10. vue2.x学习笔记(二)

    接着前面的内容:https://www.cnblogs.com/yanggb/p/12555836.html. 声明式渲染 vue的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进DOM的系统. ...