思路很乱,写个博客理一理。

缩点 + dp。

首先发现把一个环上的边反向是意义不大的,这样子不但不好算,而且相当于浪费了一次反向的机会。反正一个强连通分量里的点绕一遍都可以走到,所以我们缩点之后把一个强连通分量放在一起处理。

设$st$表示缩点之后$1$所在的点,设$f_{x}$表示从$st$走到$x$的最长链,$g_{x}$表示从$x$走到$st$的最长链,因为把一个$DAG$上的边反向一下并不会走重复的点,那么我们最后枚举一下边$(x, y)$,把它反向,这样子$f_{x} + g_{y} - siz_{st}$就可以成为备选答案,更新$ans$即可。

注意到有可能整个图强连通,所以$ans$应初始化为$siz_{st}$。

考虑一下$f$和$g$怎么求,一种想法是$st$开始的最长路,我们可以在反图和正图上分别跑一遍$spfa$,这样子可以通过,但是我并不清楚在$DAG$上$spfa$的表现是不是稳定的,另一种想法就是$dp$,直接记搜搞一搞,但是直接记搜是错误的,因为有一些点是不可能走到的,所以在$dp$之前要先$dfs$一遍标记出所有的合法点,然后再进行记搜即可。

时间复杂度$O(n)$。

放上写得很丑很长还可能有锅的代码。

你谷的数据是真的水。

Code:

#include <cstdio>
#include <cstring>
#include <vector>
using namespace std; const int N = 1e5 + ; int n, m, tot = , head[N], dfsc = , dfn[N], low[N];
int scc = , f[N], g[N], inx[N], iny[N], top = , sta[N], bel[N], siz[N];
bool vis[N], ok[N];
vector <int> G1[N], G2[N]; struct Edge {
int to, nxt;
} e[N]; inline void add(int from, int to) {
e[++tot].to = to;
e[tot].nxt = head[from];
head[from] = tot;
} inline void read(int &X) {
X = ; char ch = ; int op = ;
for(; ch > '' || ch < ''; ch = getchar())
if(ch == '-') op = -;
for(; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} inline int min(int x, int y) {
return x > y ? y : x;
} void tarjan(int x) {
low[x] = dfn[x] = ++dfsc;
vis[x] = , sta[++top] = x;
for(int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if(!dfn[y]) {
tarjan(y);
low[x] = min(low[x], low[y]);
} else if(vis[y])
low[x] = min(low[x], dfn[y]);
} if(low[x] == dfn[x]) {
++scc;
for(; sta[top + ] != x; --top) {
vis[sta[top]] = ;
siz[scc]++;
bel[sta[top]] = scc;
}
}
} inline void chkMax(int &x, int y) {
if(y > x) x = y;
} void dfs1(int x) {
ok[x] = , vis[x] = ;
for(unsigned int i = ; i < G1[x].size(); i++) {
int y = G1[x][i];
dfs1(y);
}
} int dp1(int x) {
if(vis[x]) return f[x];
vis[x] = ;
int res = ;
for(unsigned int i = ; i < G2[x].size(); i++) {
int y = G2[x][i];
if(ok[y]) chkMax(res, dp1(y));
}
f[x] = res + siz[x];
return f[x];
} void dfs2(int x) {
ok[x] = , vis[x] = ;
for(unsigned int i = ; i < G2[x].size(); i++) {
int y = G2[x][i];
dfs2(y);
}
} int dp2(int x) {
if(vis[x]) return g[x];
vis[x] = ;
int res = ;
for(unsigned int i = ; i < G1[x].size(); i++) {
int y = G1[x][i];
if(ok[y]) chkMax(res, dp2(y));
}
g[x] = res + siz[x];
return g[x];
} int main() {
// freopen("testdata.in", "r", stdin); read(n), read(m);
for(int i = ; i <= m; i++) {
read(inx[i]), read(iny[i]);
add(inx[i], iny[i]);
} for(int i = ; i <= n; i++)
if(!dfn[i]) tarjan(i); for(int i = ; i <= m; i++) {
if(bel[inx[i]] == bel[iny[i]]) continue;
G1[bel[inx[i]]].push_back(bel[iny[i]]);
G2[bel[iny[i]]].push_back(bel[inx[i]]);
} memset(vis, , sizeof(vis));
memset(ok, , sizeof(ok));
dfs1(bel[]); memset(vis, , sizeof(vis));
for(int i = ; i <= scc; i++) {
if(ok[i]) dp1(i);
} memset(vis, , sizeof(vis));
memset(ok, , sizeof(ok));
dfs2(bel[]); memset(vis, , sizeof(vis));
for(int i = ; i <= scc; i++) {
if(ok[i]) dp2(i);
} /* for(int i = 1; i <= scc; i++)
printf("%d ", g[i]);
printf("\n");
for(int i = 1; i <= scc; i++)
printf("%d ", f[i]);
printf("\n"); */ int ans = siz[bel[]];
for(int i = ; i <= m; i++) {
int u = bel[iny[i]], v = bel[inx[i]];
if(u == v) continue;
if(f[u] && g[v]) chkMax(ans, f[u] + g[v] - siz[bel[]]);
} printf("%d\n", ans);
return ;
}

Luogu 3119 [USACO15JAN]草鉴定Grass Cownoisseur的更多相关文章

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

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

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

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

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

    原题链接 显然一个强连通分量里所有草场都可以走到,所以先用\(tarjan\)找强连通并缩点. 对于缩点后的\(DAG\),先复制一张新图出来,然后对于原图中的每条边的终点向新图中该边对应的那条边的起 ...

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

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

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

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

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

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

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

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

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

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

  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. ADO.Net创建数据模型和数据访问类及泛型集合

    数据模型和数据访问类:数据模型: 使用面向对象中的封装特性,将数据表中的行数据组成一个同样结构的对象,来单独使用: 数据访问类: 将某一个表的全部增删改查操作的方法写进去,方便统一管理和调用: 数据模 ...

  2. metasploit framework(七):密码嗅探

    run 当嗅探到流量中的用户密码信息时打印出来,目前只支持FTP,http get , pop3 还可以对抓包文件,进行密码提取,设置需要提取的文件路径 run就能提取里面的用户密码信息 查看和停掉某 ...

  3. mac通过命令行获取证书和配置文件过期时间

      背景:ios打包证书的profile配置文件过期了,导致以前已经打完的测试包不能安装.所以需要加上检测机制,在打包时提示证书是否将要过期,如果要过期了给出提示   方案: 1.查找profile配 ...

  4. Jboss 数据源密码明文加密

    转载:https://blog.csdn.net/iberr/article/details/40896479 备注:解密小程序没有测试,知识了解了加密解密过程.对自己的帮助是看懂了连接数据库的配置, ...

  5. java使用正则表达式

    package com.regexp; import java.util.regex.Matcher; import java.util.regex.Pattern; public class Tes ...

  6. dedecms list 添加自定义字段方法

    在内容模型管理中,添加字段时需这样:

  7. Maven 标签

    scope 1.compile:默认值 他表示被依赖项目需要参与当前项目的编译,还有后续的测试,运行周期也参与其中,是一个比较强的依赖.打包的时候通常需要包含进去 2.test:依赖项目仅仅参与测试相 ...

  8. TOJ5398: 签到大富翁(简单模拟) and TOJ 5395: 大于中值的边界元素(数组的应用)

    Python代码!!! 5395 传送门:http://acm.tzc.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=53 ...

  9. PHP调用外部程序的方法

    很多情况下需要php调用其他程序如shell命令.shell脚本.可执行程序等等,此时需要使用到诸如exec/system/popen/proc_open等函数,每种函数有各自适合使用的场景以及需要注 ...

  10. Python爬虫项目--爬取猫眼电影Top100榜

    本次抓取猫眼电影Top100榜所用到的知识点: 1. python requests库 2. 正则表达式 3. csv模块 4. 多进程 正文 目标站点分析 通过对目标站点的分析, 来确定网页结构,  ...