首先看得出缩点的套路。跑出DAG之后,考虑怎么用逆行条件。首先可以不用,这样只能待原地不动。用的话,考虑在DAG上向后走,必须得逆行到1号点缩点后所在点的前面,才能再走回去。

于是统计从1号点缩点所在点到所有走到的点的最长距离,以及所有可以走到1号的点到1号的最长距离。然后,看在哪里逆行,可以暴力枚举每条边,然后把两边连接的点用预处理好的信息更新答案即可。这个可以使用正/反向跑图加记忆化。

注意一点:这样统计是不会重复统计的,因为如果存在点可以从1号经过,逆行之后又经过这个点,回到1号点,那就有环了,不是DAG。

忽略点($WA\times 1$):1号点也可能在环内,要以缩点之后的代表点来考虑。

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define dbg(x) cerr << #x << " = " << x <<endl
#define dbg2(x,y) cerr<< #x <<" = "<< x <<" "<< #y <<" = "<< y <<endl
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
template<typename T>inline T _min(T A,T B){return A<B?A:B;}
template<typename T>inline T _max(T A,T B){return A>B?A:B;}
template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,):;}
template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,):;}
template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
template<typename T>inline T read(T&x){
x=;int f=;char c;while(!isdigit(c=getchar()))if(c=='-')f=;
while(isdigit(c))x=x*+(c&),c=getchar();return f?x=-x:x;
}
const int N=1e5+,INF=0x3f3f3f3f;
struct thxorz{int to,nxt;}G[N],dag[N],rdag[N];
int Head[N],dhd[N],rhd[N],tot1,tot2,tot3,frm[N];
int n,m;
inline void Addedge(int x,int y){G[++tot1].to=y,G[tot1].nxt=Head[x],Head[x]=tot1;frm[tot1]=x;}
inline void AddDAG(int x,int y){dag[++tot2].to=y,dag[tot2].nxt=dhd[x],dhd[x]=tot2;}
inline void AddrDAG(int x,int y){rdag[++tot3].to=y,rdag[tot3].nxt=rhd[x],rhd[x]=tot3;}
#define y G[j].to
int dfn[N],low[N],cnt,instk[N],stk[N],Top,val[N],bel[N];
void tarjan(int x){
dfn[x]=low[x]=++cnt,stk[++Top]=x,instk[x]=;
for(register int j=Head[x];j;j=G[j].nxt){
if(!dfn[y])tarjan(y),MIN(low[x],low[y]);
else if(instk[y])MIN(low[x],dfn[y]);
}
if(dfn[x]==low[x]){int tmp;do instk[tmp=stk[Top--]]=,bel[tmp]=x,++val[x];while(tmp^x);}
}
#undef y
int ans1[N],ans2[N],vis[N],ans;
#define y rdag[j].to
int dp1(int x){//dbg2(x,val[x]);
if(vis[x])return ans1[x];
vis[x]=;
for(register int j=rhd[x];j;j=rdag[j].nxt)MAX(ans1[x],dp1(y)+val[x]);
return ans1[x];
}
#undef y
#define y dag[j].to
int dp2(int x){
if(vis[x])return ans2[x];
vis[x]=;
for(register int j=dhd[x];j;j=dag[j].nxt)MAX(ans2[x],dp2(y)+val[x]);
return ans2[x];
}
#undef y
int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout);
read(n),read(m);
for(register int i=,x,y;i<=m;++i)read(x),read(y),Addedge(x,y);
for(register int i=;i<=n;++i)if(!dfn[i])tarjan(i);
for(register int t=,u,v;t<=tot1;++t){
u=frm[t],v=G[t].to;
if(bel[u]^bel[v])AddDAG(bel[u],bel[v]),AddrDAG(bel[v],bel[u]);//CAUTION!LOOP!
}
fill(ans1+,ans1+n+,-INF),fill(ans2+,ans2+n+,-INF);ans1[bel[]]=ans2[bel[]]=;
for(register int i=;i<=n;++i)if(val[i])dp1(i);
memset(vis,,sizeof vis);ans=val[bel[]];
for(register int i=;i<=n;++i)if(val[i])dp2(i);
for(register int t=,u,v;t<=tot2;++t){
u=rdag[t].to,v=dag[t].to;
MAX(ans,ans1[v]+ans2[u]+val[bel[]]);
}
printf("%d\n",ans);
return ;
}

问题总结:缩点记忆化dp要常检查两样:初始化及边界、缩点是否影响了什么(会不会出错)。

BZOJ3887 [Usaco2015 Jan]Grass Cownoisseur[缩点]的更多相关文章

  1. BZOJ3887 [Usaco2015 Jan] Grass Cownoisseur 【tarjan】【DP】*

    BZOJ3887 [Usaco2015 Jan] Grass Cownoisseur Description In an effort to better manage the grazing pat ...

  2. bzoj3887: [Usaco2015 Jan]Grass Cownoisseur

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

  3. [补档][Usaco2015 Jan]Grass Cownoisseur

    [Usaco2015 Jan]Grass Cownoisseur 题目 给一个有向图,然后选一条路径起点终点都为1的路径出来,有一次机会可以沿某条边逆方向走,问最多有多少个点可以被经过? (一个点在路 ...

  4. [bzoj3887][Usaco2015 Jan]Grass Cownoisseur_trajan_拓扑排序_拓扑序dp

    [Usaco2015 Jan]Grass Cownoisseur 题目大意:给一个有向图,然后选一条路径起点终点都为1的路径出来,有一次机会可以沿某条边逆方向走,问最多有多少个点可以被经过?(一个点在 ...

  5. [Usaco2015 Jan]Grass Cownoisseur Tarjan缩点+SPFA

    考试的时候忘了缩点,人为dfs模拟缩点,没想到竟然跑了30分,RB爆发... 边是可以重复走的,所以在同一个强连通分量里,无论从那个点进入从哪个点出,所有的点一定能被一条路走到. 要使用缩点. 然后我 ...

  6. 洛谷—— 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 ...

  7. [Usaco2015 Jan]Grass Cownoisseur 图论 tarjan spfa

    先缩点,对于缩点后的DAG,正反跑spfa,枚举每条边进行翻转即可 #include<cstdio> #include<cstring> #include<iostrea ...

  8. BZOJ 3887/Luogu P3119: [Usaco2015 Jan]Grass Cownoisseur (强连通分量+最长路)

    分层建图,反向边建在两层之间,两层内部分别建正向边,tarjan缩点后,拓扑排序求一次1所在强连通分量和1+n所在强联通分量的最长路(长度定义为路径上的强联通分量内部点数和).然后由于1所在强连通分量 ...

  9. BZOJ 3887: [Usaco2015 Jan]Grass Cownoisseur tarjan + spfa

    Code: #include <bits/stdc++.h> #define setIO(s) freopen(s".in","r",stdin) ...

随机推荐

  1. 最新 东方明珠java校招面经 (含整理过的面试题大全)

    从6月到10月,经过4个月努力和坚持,自己有幸拿到了网易雷火.京东.去哪儿.东方明珠等10家互联网公司的校招Offer,因为某些自身原因最终选择了东方明珠.6.7月主要是做系统复习.项目复盘.Leet ...

  2. leveldb单元测试之宏定义源码剖析

    前言 leveldb 是一个库,没有 main() 函数入口, 故非常难理清其中的代码逻辑.但好在库中有非常多的单元测试代码,帮助读者理解其中的各个模块的功能.然而,测试代码个人觉得一开始看时非常费解 ...

  3. [转帖]GNU/Linux与开源文化的那些人和事

    GNU/Linux与开源文化的那些人和事 时间:2015-09-24   作者:admin 分类:新手入门 阅读:167次 http://embeddedlinux.org.cn/emb-linux/ ...

  4. Python中几个必须知道的函数

    Python中自带了几个比较有意思的函数,一般在面试或者笔试基础的时候会问到,其中3个就是map.filter.reduce函数. 1.map(function, iterable) 它第一个要传的元 ...

  5. python 入门(基础)

    1. python的常见数据类型(str , list ,dict,set) str (字符串的操作方法) astr = " Hello Workd " astr.strip() ...

  6. 异常处理 try

    语法错误 这种错误的不能使用异常处理,你自己粗心写错怪谁,哼哼哼 比如说少冒号啦,丢了括号啦 逻辑错误 try: num = int(input("请输入数字")) print(1 ...

  7. spark异常篇-关闭程序

    在运行 spark 程序时,出于某种原因,我想停止运行,狂按 ctrl+c 不一定起作用 以下两种情况是不好关闭的 1. cluster 运行模式 2. SparkStreaming 程序 本文旨在收 ...

  8. 微信公众号支付备忘及填坑之路-java

    一.背景 最近公司给第三方开发了一个公众号,其中最重要的功能是支付,由于是第一次开发,遇到的坑特别的多,截止我写博客时,支付已经完成,在这里我把遇到的坑记录一下(不涉及退款).不得不吐槽一下,腾讯这么 ...

  9. kubernetes 集群内部访问外部的数据库endpoint

    k8s访问集群外独立的服务最好的方式是采用Endpoint方式,以mysql服务为例: 创建mysql-service.yaml apiVersion: v1 kind: Service metada ...

  10. 关于SpringMVC映射模型视图的几点小事

    一.SpringMVC概述 SpringMVC为展现层提供的基于MVC设计理念的优秀的Web框架,是目前最主流的MVC框架之一. SpringMVC通过一套MVC注解,让POJO成为处理请求的控制器, ...