题目大意

  给出一个有向图,问将图中的哪一个边翻转,会使节点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;
}

  

最新文章

  1. android wifi P2P CONNECT, INVITE和JOIN流程选择
  2. OWIN的理解和实践(三) –Middleware开发入门
  3. iOS解析数据时Error=3840
  4. windows磁盘分区
  5. web测试一般分为那几个阶段,哪些阶段是可以用工具实现的,都有些什么工具,哪些阶段必须要人工手动来实现呢?
  6. elk是指logstash,elasticsearch,kibana三件套,这三件套可以组成日志分析和监控工具
  7. mac 10.8 编译提示找不到GCC
  8. 30分钟Git命令入门到放弃
  9. WebBrowser控件使用相关
  10. uva 10032 Problem F: Tug of War
  11. C++中的句柄类
  12. Opencv2系列学习笔记8(图像滤波)
  13. c#后台调用API
  14. PHP下安装memcached
  15. BZOJ-6-2460: [BeiJing2011]元素-线性基
  16. 【推荐】Nginx基础知识之————多模块(非覆盖安装、RTMP在线人数实例安装测试)
  17. oozie 安装过程详解
  18. z-index层级顺序 opacity透明度 display: none 模态框实现
  19. 通过Get-Group导出组的成员
  20. Map类

热门文章

  1. ArcGIS Android工程迁移到其他电脑不能打开的问题
  2. 移动web——基本知识点总结
  3. ASP.net参数传递总结
  4. JQuery文档加载完成执行js的几种方法
  5. Python语言之控制流(if...elif...else,while,for,break,continue)
  6. (转)Hibernate框架基础——cascade属性
  7. Address space layout randomization
  8. C# Tuple 创建一个新二元集合
  9. Makefile精髓篇【转】
  10. Linux 通过cksum 来判断文件是否是相同