P3119 [USACO15JAN]草鉴定[SCC缩点+SPFA]
题目描述
约翰有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]的更多相关文章
- 洛谷 P3119 [USACO15JAN]草鉴定Grass Cownoisseur (SCC缩点,SPFA最长路,枚举反边)
P3119 [USACO15JAN]草鉴定Grass Cownoisseur 题目描述 In an effort to better manage the grazing patterns of hi ...
- 洛谷 P3119 [USACO15JAN]草鉴定Grass Cownoisseur 解题报告
P3119 [USACO15JAN]草鉴定Grass Cownoisseur 题目描述 约翰有\(n\)块草场,编号1到\(n\),这些草场由若干条单行道相连.奶牛贝西是美味牧草的鉴赏家,她想到达尽可 ...
- 洛谷——P3119 [USACO15JAN]草鉴定Grass Cownoisseur
P3119 [USACO15JAN]草鉴定Grass Cownoisseur 题目描述 In an effort to better manage the grazing patterns of hi ...
- [Luogu P3119] [USACO15JAN]草鉴定Grass Cownoisseur (缩点+图上DP)
题面 传送门:https://www.luogu.org/problemnew/show/P3119 Solution 这题显然要先把缩点做了. 然后我们就可以考虑如何处理走反向边的问题. 像我这样的 ...
- P3119 [USACO15JAN]草鉴定Grass Cownoisseur
题目描述 In an effort to better manage the grazing patterns of his cows, Farmer John has installed one-w ...
- 洛谷P3119 USACO15JAN 草鉴定
题目描述 In an effort to better manage the grazing patterns of his cows, Farmer John has installed one-w ...
- luogu P3119 [USACO15JAN]草鉴定Grass Cownoisseur
题目描述 In an effort to better manage the grazing patterns of his cows, Farmer John has installed one-w ...
- luogu3119/bzoj3887 草鉴定 (tarjan缩点+spfa)
首先缩一波点,就变成了一个DAG,边权是出点的大小 那我们走到某个点的时候可能会有两种状态:已经走过反边或者没走过 于是就把一个点拆成两层(x和x+N),第二层的点表示我已经走过反边了,每层中的边和原 ...
- 洛谷—— 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 ...
随机推荐
- @Component和@Configuration作为配置类的差别
https://blog.csdn.net/long476964/article/details/80626930 虽然Component注解也会当做配置类,但是并不会为其生成CGLIB代理Class ...
- SpringBoot + Mybaties的逆向工程有数据库生成domain的过程
环境: jdk1.8 (适合springboot2.X以上版本) Maven(3.3.X以上) spring boot 2.1.6 Idea 2019.1\ 这里随便填 选择相应的Jar,如以下的勾 ...
- 永久解决Sublime包管理package control 打开install package报错 There are no packages available for installation
很多用户在使用sumblime安装插件的时候,打开package control的install package会出现报错:There are no packages available for in ...
- strings包 — 汇总
转自:https://www.jb51.net/article/148388.htm strings 包中的函数和方法 // Count 计算字符串 sep 在 s 中的非重叠个数 // 如果 sep ...
- SpringAOP异常:org.springframework.aop.aspectj.AspectJExpressionPointcut cannot be cast to com.....
Exception in thread "main" java.lang.ClassCastException: org.springframework.aop.aspectj.A ...
- Linux系统下Redis单机版的安装详细教程
Linux系统下Redis单机版的安装详细教程 1.下载软件安装包并上传到root目录 这里以旧版本的3.0进行安装,比较成熟稳定,具体软件可以通过qq群534073451文件下载
- ssh常用操作
介绍ssh.sshpass.scp等linux下远程操作常用的命令 ssh 通过终端远程linux服务器的常用命令 ssh root@192.168.1.100 #以root用户链接到目标服务器,连通 ...
- Pycharm下直接升级库所遇到的'main'问题
Pycharm下直接升级库所遇到的pip模块中无'main'问题 Author : Benjamin142857 Date : 8/19/2018 对于Pycharm中直接升级库,只需在 \(Sett ...
- AS3中 is,as,typeof的区别
AS3中 is,as,typeof的区别 . var my_num:Number=9;trace(typeof my_num);var my_object:Array=["语文", ...
- spring bean是什么
Spring有跟多概念,其中最基本的一个就是bean,那到底spring bean是什么? Bean是Spring框架中最核心的两个概念之一(另一个是面向切面编程AOP). 是否正确理解 Bean 对 ...