Luogu 3119 [USACO15JAN]草鉴定Grass Cownoisseur
思路很乱,写个博客理一理。
缩点 + 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的更多相关文章
- luogu P3119 [USACO15JAN]草鉴定Grass Cownoisseur
题目描述 In an effort to better manage the grazing patterns of his cows, Farmer John has installed one-w ...
- [Luogu P3119] [USACO15JAN]草鉴定Grass Cownoisseur (缩点+图上DP)
题面 传送门:https://www.luogu.org/problemnew/show/P3119 Solution 这题显然要先把缩点做了. 然后我们就可以考虑如何处理走反向边的问题. 像我这样的 ...
- 洛谷3119 [USACO15JAN]草鉴定Grass Cownoisseur
原题链接 显然一个强连通分量里所有草场都可以走到,所以先用\(tarjan\)找强连通并缩点. 对于缩点后的\(DAG\),先复制一张新图出来,然后对于原图中的每条边的终点向新图中该边对应的那条边的起 ...
- 洛谷 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 ...
- [USACO15JAN]草鉴定Grass Cownoisseur(分层图+tarjan)
[USACO15JAN]草鉴定Grass Cownoisseur 题目描述 In an effort to better manage the grazing patterns of his cows ...
- 洛谷 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
草鉴定Grass Cownoisseur 题目链接 约翰有n块草场,编号1到n,这些草场由若干条单行道相连.奶牛贝西是美味牧草的鉴赏家,她想到达尽可能多的草场去品尝牧草. 贝西总是从1号草场出发,最后 ...
- 洛谷—— 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 ...
随机推荐
- XML 可扩展标记语言
因 为XML实在是太重要了,而且被广泛应用!不论是数据存储,还是其他方面,如配置文件等.XML是一种对独立于任何编程语言的数据进行编码的机制.在数据 交换领域,正在变得非常流行!因为他的基于节点的存储 ...
- 在Laravel外独立使用laravel-mongodb
laravel框架外部使用laravel-mongodb 插件 下载安装方式主要根据github上的参考: https://github.com/jenssegers/laravel-mongodb# ...
- Light Probe
[Light Probe] Light Probes provide a way to capture and use information about light that is passing ...
- Frame animation
[Frame animation] An animation defined in XML that shows a sequence of images in order (like a film) ...
- Windows 2012设置允许单个用户连接多个会话的方法
WINDOWS 2012 服务器默认只允许单个用户连接一个远程桌面会话,如果已有连接登陆,另外的连接再登陆会踢掉之前的连接.如果需要两个远程桌面同时连接 找到:HKEY_LOCAL_MACHINE\S ...
- day22 面向对象基础
1.什么是面向过程 在介绍面向对象之前,要先明确面向过程 在这之前我们所写的任何代码都是面向过程的 什么是面向过程? 是一种编程思想 面对 朝向 在编写代码时,要时刻想着过程这两个字 过程指的是什么? ...
- Appium1.6 定位iOS元素和操作元素
元素定位方式 第一种:通过Appium1.6的Inspector来查看 具体安装方式前面的随笔已经介绍了:http://www.cnblogs.com/meitian/p/7360017.html ...
- springboot security 获取当前登录用户名
System.out.println(((User)SecurityContextHolder.getContext().getAuthentication().getPrincipal()).get ...
- Linux 字符设备驱动及一些简单的Linux知识
一.linux系统将设备分为3类:字符设备.块设备.网络设备 1.字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据.字符设备是面向流的设备,常见 ...
- 第十章 优先级队列 (a1)需求与动机