BZOJ3887 [Usaco2015 Jan]Grass Cownoisseur[缩点]
首先看得出缩点的套路。跑出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[缩点]的更多相关文章
- BZOJ3887 [Usaco2015 Jan] Grass Cownoisseur 【tarjan】【DP】*
BZOJ3887 [Usaco2015 Jan] Grass Cownoisseur Description In an effort to better manage the grazing pat ...
- bzoj3887: [Usaco2015 Jan]Grass Cownoisseur
题意: 给一个有向图,然后选一条路径起点终点都为1的路径出来,有一次机会可以沿某条边逆方向走,问最多有多少个点可以被经过?(一个点在路径中无论出现多少正整数次对答案的贡献均为1) =>有向图我们 ...
- [补档][Usaco2015 Jan]Grass Cownoisseur
[Usaco2015 Jan]Grass Cownoisseur 题目 给一个有向图,然后选一条路径起点终点都为1的路径出来,有一次机会可以沿某条边逆方向走,问最多有多少个点可以被经过? (一个点在路 ...
- [bzoj3887][Usaco2015 Jan]Grass Cownoisseur_trajan_拓扑排序_拓扑序dp
[Usaco2015 Jan]Grass Cownoisseur 题目大意:给一个有向图,然后选一条路径起点终点都为1的路径出来,有一次机会可以沿某条边逆方向走,问最多有多少个点可以被经过?(一个点在 ...
- [Usaco2015 Jan]Grass Cownoisseur Tarjan缩点+SPFA
考试的时候忘了缩点,人为dfs模拟缩点,没想到竟然跑了30分,RB爆发... 边是可以重复走的,所以在同一个强连通分量里,无论从那个点进入从哪个点出,所有的点一定能被一条路走到. 要使用缩点. 然后我 ...
- 洛谷—— 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 ...
- [Usaco2015 Jan]Grass Cownoisseur 图论 tarjan spfa
先缩点,对于缩点后的DAG,正反跑spfa,枚举每条边进行翻转即可 #include<cstdio> #include<cstring> #include<iostrea ...
- BZOJ 3887/Luogu P3119: [Usaco2015 Jan]Grass Cownoisseur (强连通分量+最长路)
分层建图,反向边建在两层之间,两层内部分别建正向边,tarjan缩点后,拓扑排序求一次1所在强连通分量和1+n所在强联通分量的最长路(长度定义为路径上的强联通分量内部点数和).然后由于1所在强连通分量 ...
- BZOJ 3887: [Usaco2015 Jan]Grass Cownoisseur tarjan + spfa
Code: #include <bits/stdc++.h> #define setIO(s) freopen(s".in","r",stdin) ...
随机推荐
- 《PC Assembly Language》读书笔记
本书下载地址:pcasm-book. 前言 8086处理器只支持实模式(real mode),不能满足安全.多任务等需求. Q:为什么实模式不安全.不支持多任务?为什么虚模式能解决这些问题? A: 以 ...
- [LuoguP2143]巨额资金_Kruskal_Matrix-Tree定理
巨额资金 题目链接:https://www.luogu.org/problem/P2143 数据范围:略. 题解: 有一个条件是每种权值的边最多是$10$条. 但是并不知道怎么用.... 不过有一点我 ...
- [转帖]SPARC简介
https://www.cnblogs.com/chaohm/p/5674886.html 1. 概述 SPARC(Scalable Processor ARChitecture,可扩展处理器架 ...
- [github] 关于华为鸿蒙OS
English Docs | 中文文档 | Türkçe Dökümanlar HarmonyOS Ⅰ. 鸿蒙系统简介 鸿蒙系统(HarmonyOS),是第一款基于微内核的全场景分布式OS,是华为自主 ...
- curl使用举例
我在银行工作时,一个具体的用例:shell脚本中使用的 sendAddr=`echo http:192.168.1.100:8080/cloud-monitor/perfaddperf` SendDa ...
- SpringBoot 项目如何在tomcat容器中运行
一. SpringBoot内嵌容器的部署方式 SpringBoot内部默认提供内嵌的tomcat容器,所以可以直接打成jar包,丢到服务器上的任何一个目录,然后在当前目录下执行java -jar de ...
- 大话数据结构(8) 串的模式匹配算法(朴素、KMP、改进算法)
--喜欢记得关注我哟[shoshana]-- 目录 1.朴素的模式匹配算法2.KMP模式匹配算法 2.1 KMP模式匹配算法的主体思路 2.2 next[]的定义与求解 2.3 KMP完整代码 2.4 ...
- error LNK2001: unresolved external symbol __imp__closesocket@4
环境:Visual C++6.0 问题:链接错误 描述: Linking... NetSrv.obj : error LNK2001: unresolvedexternal symbol __imp_ ...
- css 颜色自动变化 炫彩
.layui-icon-login-qq:hover{ color:rgb(0, 156, 255); transition: 0.5s; animation:change 10s linear 0s ...
- Jmeter4.0---- 修改jmeter源代码(18)
1.说明 jmeter本身功能很强大,但是在使用的时候我们会发现有些想法jmeter无法帮我们实现,这个时候就需要我们细节去修改一下它的源代码,来满足我们的需求. * 仅供参考 2.步骤 第一步: j ...