题目描述

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

贝西总是从1号草场出发,最后回到1号草场。她想经过尽可能多的草场,贝西在通一个草场只吃一次草,所以一个草场可以经过多次。因为草场是单行道连接,这给贝西的品鉴工作带来了很大的不便,贝西想偷偷逆向行走一次,但最多只能有一次逆行。问,贝西最多能吃到多少个草场的牧草。

解析

此题就是在Tarjan的板子上玩了点花样,然鹅窝这种题都写不出来,看来我还需要提升。

首先容易看出来一个强连通分量里面草是随便吃而不会出现逆行的,所以我们先缩点。

以下我们考虑缩点后的图。

这个逆行一次回到起点的处理就比较麻烦了,我们不妨把这条路拆成两部分,分别是起点1号节点所在强连通分量到逆行边起点的最长路和逆行边终点回到起点的最长路。

我到这就不知道怎么处理逆行边终点回到起点的最长路了(科技树点歪)。试想如果直接拿逆行边终点跑最长路,T是妥妥的。

一个行之有效的解决方法是建反图,然后在反图上以1号节点所在强连通分量为起点跑最长路,得到的就是原图以1号节点所在强连通分量为终点的最长路,这个其实不难理解。

而且这样并不会导致吃两次草,即两次最长路的路径发生重叠,可以用反证法简单证明,这样的情况被缩点所排除了。

因为是DAG,所以最长路是可解的,我们SPFA或者拓扑去求就行了。

注意细节,我们对1号节点所在强连通分量是统计了两次的,最后要减去一次。

参考代码

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<ctime>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#define N 100010
#define INF 0x3f3f3f3f
#define IN freopen("data.in","r",stdin);
using namespace std;
inline int read()
{
int f=1,x=0;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
struct rec{
int next,ver;
}g[N<<1],G[N],G2[N];
int head[N],tot,headG[N],totG,headG2[N],totG2,n,m,dfn[N],low[N];
int stack[N],top,scc[N],idt,cnt,c[N],d1[N],d2[N],s;
bool ins[N],v[N];
inline void add(int x,int y)
{
g[++tot].ver=y;
g[tot].next=head[x],head[x]=tot;
}
inline void addG(int x,int y)
{
G[++totG].ver=y;
G[totG].next=headG[x],headG[x]=totG;
}
inline void addG2(int x,int y)
{
G2[++totG2].ver=y;
G2[totG2].next=headG2[x],headG2[x]=totG2;
}
inline void tarjan(int x)
{
dfn[x]=low[x]=++cnt;
stack[++top]=x,ins[x]=1;
for(int i=head[x];i;i=g[i].next){
int y=g[i].ver;
if(!dfn[y]){
tarjan(y);
low[x]=min(low[x],low[y]);
}
else if(ins[y]) low[x]=min(low[x],dfn[y]);
}
if(low[x]==dfn[x]){
++idt;int y;
do{
y=stack[top--],ins[y]=0;
if(y==1) s=idt;
c[y]=idt,scc[idt]++;
}while(x!=y);
}
}
inline void spfa1()
{
memset(d1,0,sizeof(d1));
queue<int> q;
d1[s]=scc[s];q.push(s);
while(q.size()){
int x=q.front();q.pop();
v[x]=0;
for(int i=headG[x];i;i=G[i].next){
int y=G[i].ver;
if(d1[y]<d1[x]+scc[y]){
d1[y]=d1[x]+scc[y];
if(!v[y]) v[y]=1,q.push(y);
}
}
}
}
inline void spfa2()
{
memset(d2,0,sizeof(d2));
queue<int> q;
d2[s]=scc[s];q.push(s);
while(q.size()){
int x=q.front();q.pop();
v[x]=0;
for(int i=headG2[x];i;i=G2[i].next){
int y=G2[i].ver;
if(d2[y]<d2[x]+scc[y]){
d2[y]=d2[x]+scc[y];
if(!v[y]) v[y]=1,q.push(y);
}
}
}
}
int main()
{
//IN
n=read(),m=read();
for(int i=1;i<=m;++i){
int u,v;
u=read(),v=read();
add(u,v);
}
for(int i=1;i<=n;++i)
if(!dfn[i]) tarjan(i);
for(int x=1;x<=n;++x)
for(int i=head[x];i;i=g[i].next){
int y=g[i].ver;
if(c[x]==c[y]) continue;
addG(c[x],c[y]),addG2(c[y],c[x]);
}
int ans=scc[s];//注意有可能只有一个强连通分量,那答案就是他自己
spfa1();
spfa2();
for(int i=1;i<=idt;++i){
//这里利用到一个技巧,没有被SPFA标记的地方就是最长路径的终点,逆行边的起点
//这样就可以快速找出逆行边的位置并进行统计
//即逆行边是一条y->i的边,而利用反图恰恰可以快速找出所有这样的边
if(!v[i]&&d1[i]){
v[i]=1;
for(int j=headG2[i];j;j=G2[j].next){
int y=G2[j].ver;
if(!d2[y]) continue;//及时排除不可达情况
ans=max(ans,d1[i]+d2[y]-scc[s]);
}
}
}
cout<<ans<<endl;
return 0;
}

P3119 [USACO15JAN]草鉴定[SCC缩点+SPFA]的更多相关文章

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

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

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

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

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

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

  4. [Luogu P3119] [USACO15JAN]草鉴定Grass Cownoisseur (缩点+图上DP)

    题面 传送门:https://www.luogu.org/problemnew/show/P3119 Solution 这题显然要先把缩点做了. 然后我们就可以考虑如何处理走反向边的问题. 像我这样的 ...

  5. P3119 [USACO15JAN]草鉴定Grass Cownoisseur

    题目描述 In an effort to better manage the grazing patterns of his cows, Farmer John has installed one-w ...

  6. 洛谷P3119 USACO15JAN 草鉴定

    题目描述 In an effort to better manage the grazing patterns of his cows, Farmer John has installed one-w ...

  7. luogu P3119 [USACO15JAN]草鉴定Grass Cownoisseur

    题目描述 In an effort to better manage the grazing patterns of his cows, Farmer John has installed one-w ...

  8. luogu3119/bzoj3887 草鉴定 (tarjan缩点+spfa)

    首先缩一波点,就变成了一个DAG,边权是出点的大小 那我们走到某个点的时候可能会有两种状态:已经走过反边或者没走过 于是就把一个点拆成两层(x和x+N),第二层的点表示我已经走过反边了,每层中的边和原 ...

  9. 洛谷—— P3119 [USACO15JAN]草鉴定Grass Cownoisseur || BZOJ——T 3887: [Usaco2015 Jan]Grass Cownoisseur

    http://www.lydsy.com/JudgeOnline/problem.php?id=3887|| https://www.luogu.org/problem/show?pid=3119 D ...

随机推荐

  1. Jacob操作ppt

    前几天使用Apache 的POI操作ppt,后来发现转成的图片出现乱码,而且处理了之后,还会有遗留 因此决定换一种处理方式 Jacob 是 JAVA-COM Bridge的缩写,是一个中间件,能够提供 ...

  2. Postman 使用方法详细介绍

    1,下载安装: https://www.getpostman.com/apps 2,打开Postman,如图所示: 3,创建一个接口项目 4,新增接口文件 5,下面以登录接口login为例,介绍如何做 ...

  3. [转帖]UID卡、CUID卡、FUID卡、UFUID卡的区别及写入方式

    UID卡.CUID卡.FUID卡.UFUID卡的区别及写入方式   版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://bl ...

  4. Apache Kafka安全| Kafka的需求和组成部分

    1.目标 - 卡夫卡安全 今天,在这个Kafka教程中,我们将看到Apache Kafka Security 的概念  .Kafka Security教程包括我们需要安全性的原因,详细介绍加密.有了这 ...

  5. 第二篇:彻底搞清楚 Spring Boot 的配置文件 application.properties

    前言 在Spring Boot中,配置文件有两种不同的格式,一个是properties,另一个是yaml. 虽然properties文件比较常见,但是相对于properties而言,yaml更加简洁明 ...

  6. Python各个岗位的开发流程

     根据张大美女提供资料微修改,在这谢谢张大美女! 1.python软件开发工程师 1.1 项目启动会 说明项目目标.阶段划分.组织结构.管理流程等关键事项. 1.2 需求调研 由用户提出,描述产品的功 ...

  7. input获得焦点时,如何让外边框不变蓝

    border 可应用于几乎所有有形的html元素,而outline 是针对链接.表单控件和ImageMap等元素设计. outline的效果将随元素的 focus 而自动出现,相应的随 blur 而自 ...

  8. SpringCloud之Hystrix集群及集群监控turbine

    目的: Hystrix集群及监控turbine Feign.Hystrix整合之服务熔断服务降级彻底解耦 集群后超时设置 Hystrix集群及监控turbine 新建一个springboot工程mic ...

  9. 登录和退出Mysql

    这里介绍的是通过cmd方式登录和退出Mysql的方式 一.登录命令 登录命令:mysql.exe -h主机地址   -P端口   -u用户名    -p密码 即依次输入服务器地址.服务器监听的端口.用 ...

  10. docker-compose 单机容器编排

    docker-compose用来在单机上编排容器(定义和运行多个容器,使容器能互通) docker-compose将所管理的容器分为3层结构:project  service  container d ...