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 ...
随机推荐
- border&background1
1.border-radius border-top-left-radius:10px; = border-top-left-radius:10px 10px; (水平10px 竖直10px 被正圆切 ...
- CSS 规范 命名规则
http://nec.netease.com/standard/css-practice.html
- PowerDesigner导入sql脚本生成物理模型
https://www.cnblogs.com/zsswpb/p/5771623.html
- Kerberos 互信免登陆
第一步:机器加互信 将机器A的Kerberos name加到机器B的~/.k5login中,同时将机器B的Kerberos name加到机器A的~/.k5login中 例如:host/bjm6-193 ...
- myeclipse2014安装aptana3.4.0插件(转)
1.下载aptana3.4.0_eclipse的zip包 http://pan.baidu.com/s/1qXOiZl6 或者是:https://pan.baidu.com/s/1jIqOYcI 2 ...
- centos 6.9 NTP基准时间服务器配置
时间服务器端 yum install ntp -y vim /etc/ntp.conf 增加允许客户端访问 restrict 192.168.0.0 mask 255.255.0.0 nomodify ...
- 199. Binary Tree Right Side View (Tree, Stack)
Given a binary tree, imagine yourself standing on the right side of it, return the values of the nod ...
- phpword根据模板导出word
参考网址:http://phpword.readthedocs.io/en/latest/installing.html 在composer.json中添加 { "require" ...
- 二次注入的学习--Buy Flag(http://10.112.68.215:10002)
这次有做一个二次注入的天枢CTF题目,算是完整地理解了一遍注入的知识.来,启航. 1.判断注入点 经过对题目的实践分析,知道注册时需要输入年龄大于18岁,但在登录后界面,年龄因为太大不能接 ...
- 批处理(.bat脚本)基本命令语法
.bat脚本基本命令语法 目录批处理的常见命令(未列举的命令还比较多,请查阅帮助信息) 1.REM 和 :: 2.ECHO 和 @ 3.PAUSE 4.ERRORL ...