题目大意

  给出一个有向图,问将图中的哪一个边翻转,会使节点1所在的强连通分量内的节点数最多。输出这个节点数。

题解

  让我们看看暴力怎么做,即枚举每一条边,将其翻转,然后求节点1所在强连通分量节点数,然后取最大值。我们看到如果一条边连接的两个节点位于同一个强连通分量中,那么将这条边翻转只可能拆解已有的强连通分量,并使结果变差。因此,我们对强连通分量进行缩点(点权为强连通分量的节点个数)构成一个新图。

  所以我们要在新图中暴力吗?不可以。怎样能达到“反向边只走一次”这个限制条件呢呢?分层图就能解决这个问题。原图复制一份得到上层图。把反向边起点连在原图上,终点连在上层图上,我们要求一个原图上的1节点走向上层图1节点的点权最长路径,它只会从原图走向上层图,不会从上层图走向下层图,这样就满足限制条件了。因为是点权,故我们拆点为边(以后简称“拆点边”)。

  另外,这么做满足除了1节点外,在原图1节点到上层图1节点的路径上,不存在原图和上层图对应的拆点边计算两次的情况,因为如果计算了两次,那么在下层图上也会存在一条和整条路径在上层图上的部分相同的一条路径返回1节点,这样的路径构成了一个环,不满足强连通分量的定义。

  另外注意,当有拆点、分层图时,开的空间要写到纸上。总共100000个点,分层图*2,拆点*2,故总共*4。原先我忘了拆点还要*2。。。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <stack>
#include <cassert>
using namespace std; const int MAX_NODE = 100010, MAX_EDGE = 100010, MINF = 0xcfcfcfcf; struct TarjanGraph
{
public:
struct Block
{
int Size;
vector<int> Next;
}_blocks[MAX_NODE];
int BlockCnt; private:
struct Node
{
vector<Node*> Next;
int DfsN, Low, BlockIn;
bool InStack;
}_nodes[MAX_NODE];
int DfsCnt, TotNode;
stack<Node*> St; void Destack(Node *cur)
{
BlockCnt++;
Node *temp;
do {
temp = St.top();
St.pop();
temp->BlockIn = BlockCnt;
temp->InStack = false;
_blocks[BlockCnt].Size++;
} while (temp != cur);
} void Dfs(Node *cur)
{
cur->Low = cur->DfsN = ++DfsCnt;
cur->InStack = true;
St.push(cur);
for (unsigned int i = 0; i < cur->Next.size(); i++)
{
if (!cur->Next[i]->DfsN)
{
Dfs(cur->Next[i]);
cur->Low = min(cur->Low, cur->Next[i]->Low);
}
else if (cur->Next[i]->InStack)
cur->Low = min(cur->Low, cur->Next[i]->DfsN);
}
if (cur->Low == cur->DfsN)
Destack(cur);
} public:
void Init(int totNode)
{
TotNode = totNode;
} void AddEdge(int u, int v)
{
_nodes[u].Next.push_back(_nodes + v);
} void GetBlock()
{
for (int i = 1; i <= TotNode; i++)
if (!_nodes[i].DfsN)
Dfs(_nodes + i); for (int i = 1; i <= TotNode; i++)
for (unsigned int j = 0; j < _nodes[i].Next.size(); j++)
if (_nodes[i].BlockIn != _nodes[i].Next[j]->BlockIn)
_blocks[_nodes[i].BlockIn].Next.push_back(_nodes[i].Next[j]->BlockIn);
} int GetBlockIn(int v)
{
return _nodes[v].BlockIn;
}
}g; struct TopGraph
{
private:
struct Node;
struct Edge; struct Node
{
Edge *Head;
int Dist;
int DfsN;//0:未访问 1:在系统栈内 2:处理完毕
}_nodes[MAX_NODE * 4];
int TotNode;
stack<Node*> St; struct Edge
{
Node *To;
Edge *Next;
int Weight;
}_edges[MAX_EDGE * 3 + MAX_NODE * 2];
int _eCount; void Dfs(Node *cur)
{
assert(cur->DfsN != 1);
if (cur->DfsN == 2)
return;
cur->DfsN = 1;
for (Edge *e = cur->Head; e; e = e->Next)
Dfs(e->To);
cur->DfsN = 2;
St.push(cur);
} public:
void Init(int totNode)
{
TotNode = totNode;
} void AddEdge(int u, int v, int w)
{
Node *from = _nodes + u, *to = _nodes + v;
Edge *e = _edges + ++_eCount;
e->To = to;
e->Weight = w;
e->Next = from->Head;
from->Head = e;
} int LongestPath(int s, int t)
{
Dfs(_nodes + s);
for (int i = 1; i <= TotNode; i++)
_nodes[i].Dist = MINF;
_nodes[s].Dist = 0;
while (!St.empty())
{
Node *cur = St.top();
St.pop();
for (Edge *e = cur->Head; e; e = e->Next)
e->To->Dist = max(e->To->Dist, cur->Dist + e->Weight);
}
return _nodes[t].Dist;
}
}t; int main()
{
int totNode, totEdge;
scanf("%d%d", &totNode, &totEdge);
g.Init(totNode);
for (int i = 1; i <= totEdge; i++)
{
int u, v;
scanf("%d%d", &u, &v);
g.AddEdge(u, v);
}
g.GetBlock();
t.Init(g.BlockCnt * 2);
for (int i = 1; i <= g.BlockCnt; i++)
{
t.AddEdge(i * 2 - 1, i * 2, g._blocks[i].Size);
t.AddEdge((i + totNode) * 2 - 1, (i + totNode) * 2, g._blocks[i].Size);
for (unsigned int j = 0; j < g._blocks[i].Next.size(); j++)
{
int v = g._blocks[i].Next[j];
t.AddEdge(i * 2, v * 2 - 1, 0);
t.AddEdge((i + totNode) * 2, (v + totNode) * 2 - 1, 0);
t.AddEdge(v * 2, (i + totNode) * 2 - 1, 0);
}
}
printf("%d\n", t.LongestPath(g.GetBlockIn(1) * 2 - 1, (g.GetBlockIn(1) + totNode) * 2 - 1));
return 0;
}

  

luogu3119 草鉴定的更多相关文章

  1. Luogu3119 草鉴定-Tarjan+Topsort

    Solution 简单的$Tarjan$题. 有大佬现成博客 就不写了 → 传送门 Code #include<cstdio> #include<cstring> #inclu ...

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

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

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

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

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

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

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

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

  6. 洛谷P3119草鉴定

    题目 草鉴定,tarjan可以用来缩点,优化spfa的时间, 缩点之后就是一个\(DAG\)了,因此完全可以用来跑spfa上的最长路,然后枚举每条边,查看是否这条边的两个节点分别可以到达起点所在的强连 ...

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

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

  8. luogu3119/bzoj3887 草鉴定 (tarjan缩点+spfa)

    首先缩一波点,就变成了一个DAG,边权是出点的大小 那我们走到某个点的时候可能会有两种状态:已经走过反边或者没走过 于是就把一个点拆成两层(x和x+N),第二层的点表示我已经走过反边了,每层中的边和原 ...

  9. P3119 [USACO15JAN]草鉴定Grass Cownoisseur

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

随机推荐

  1. TCP的send与recv函数小结

    Send函数: 在阻塞模式下, send函数的过程是将应用程序请求发送的数据拷贝到发送缓存中发送并得到确认后再返回.但由于发送缓存的存在,表现为:如果发送缓存大小比请求发送的大小要大,那么send函数 ...

  2. Python语言之变量2(命名规则,类型转换)

    1.命名规则 1.起始位为字母(大小写)或下划线('_') 2.其他部分为字母(大小写).下划线('_')或数字(0-9) 3.大小写敏感 2.先体验一把: #Ask the user their n ...

  3. CSS之float浮动

    CSS理解之float浮动 首先我们看看W3C给出的关于 float 的说明: 参考资料   MDN   W3C

  4. js常用方法和技巧

    随着AJAX的流行,js又得到了很多人的重视,js最大的优势就是它能够对html上的所有元素进行操作,包括创建标签元素,更改元素属性等,这样就使得我们能够利用js来实现很多的动态效果,来提供给用户更强 ...

  5. SpringMVC知识点总结一(非注解方式的处理器与映射器配置方法)

    一.SpringMVC处理请求原理图(参见以前博客) 1.  用户发送请求至前端控制器DispatcherServlet 2.  DispatcherServlet收到请求调用HandlerMappi ...

  6. php第二十一节课

    AJAX <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3 ...

  7. node版本管理工具nvm安装使用教程

    一些安装包依赖一定的node版本,可以采用nvm管理node, 可以快速的进行版本切换. 操作系统: windows10, x64 常见版本工具: 1. nvmw, nvmm install node ...

  8. 总结这几天js的学习内容

    对js中难点的理解 1.把变量对象像遍历数组一样简单 对于数组 ,迭代出来的是数组元素,对于对象 ,迭代出来的是对象的属性: var obj = { w: "wen", j: &q ...

  9. css 字体单位之间的区分以及字体响应式实现

    问题场景: 在实现响应式布局的过程中,如何设置字体大小在不同的视窗尺寸以及不同的移动设备的可读性? 需要了解的有: 1.px,em,pt之间的换算关系 1em = 16px 1px  = 1/16 e ...

  10. Luogu P3901 数列找不同

    由于技术原因,题目我贴不上了,大家点下面的链接自己去看吧^_^ P3901 数列找不同 这题第一眼看去,题面真短,有坑(flag) 在往下面看去,woc数据这么大,你要怎样. 现在一起想想想,超级侦探 ...