题目大意

  给出一个有向图,问将图中的哪一个边翻转,会使节点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. asp.net——统计输入的字符数目

    asp.net——统计输入的字符数目 题目: 在页面中有一个TextBox输入框,一个显示文字用的Label,一个提交按钮Button.在TextBox中输入一段英文字母,点击按钮提交后统计其中字母‘ ...

  2. python自动化测试框架(一)

    1.开发环境 名称 版本 系统 windows 7 python版本 2.7.14 IDE pycharm2017 2.大致框架流程 :展示了框架实现的业务流程 3.框架介绍 3.1 ======完善 ...

  3. [Windows Server 2003] ASP.net安装方法

    ★ 欢迎来到[护卫神·V课堂],网站地址:http://v.huweishen.com★ 护卫神·V课堂 是护卫神旗下专业提供服务器教学视频的网站,每周更新视频.★ 本节我们将带领大家:安装ASP.n ...

  4. 安装nodejs6.9x以后,原来在nodejs4.2.x中运行正常的ionic项目出现问题的解决

    安装nodejs6.9x以后,原来在nodejs4.2.x中运行正常的程序出现的问题.看错误信息,由于NodeJs版本升级导致的. 到提示的目录下运行:npm rebuild node-sass -g ...

  5. sql的四种连接方式

    1.内联接.(典型的联接运算,使用像 =  或 <> 之类的比较运算符).包括相等联接和自然联接. 内联接使用比较运算符根据每个表共有的列的值匹配两个表中的行.例如,检索 students ...

  6. LeetCode--寻找数组中心索引

    给定一个整数类型的数组 nums,请编写一个能够返回数组“中心索引”的方法. 我们是这样定义数组中心索引的:数组中心索引的左侧所有元素相加的和等于右侧所有元素相加的和. 如果数组不存在中心索引,那么我 ...

  7. Linux:用户和组总结

    从创建文件说起:useradd xiaomi           这里是创建了xiaomi用户 默认系统还会创建:/home/xiaomi  /var/mail/xiaomi        即家目录和 ...

  8. namespace的作用及用法

    namespace 所谓namespace,是指标识符的可见范围.C++标准库中的所有标识符都被定义在一个名为 std 的namespace 中. 一.<iostream>和<ios ...

  9. git 的简单使用(2)

    一般情况下,你通常直接在文件管理器中把没用的文件删了,或者用rm命令删了: $ rm test.txt 你可以使用 git rm test.txt来删除 然后用git commit -m " ...

  10. PAT 1057. Stack

    Stack is one of the most fundamental data structures, which is based on the principle of Last In Fir ...