luogu2149 [SDOI2009] Dlaxia的路线

题目大意

  在一个无向图中,定义两个点s,t的最短路径子图为一个极大边集,对于该边集内的所有有向边e,总存在一条起点为s,终点为t且经过边e的路径,使得该路径长度为s到t的最短路径长度。现给出一个无向图,s1, s2, t1, t2四个节点,求一条最长的路径,使得它满足下列条件之一:1. 该路径上的所有边都属于s1到t1的最短路径子图且属于s2到t2的最短路径子图;2. 该路径上的所有边都属于s1到t1的最短路径子图且属于t2到s2的最短路径子图。输出该路径的长度。

题解

  我们可以用4次Dijkstra得到s1,t1和s2,t2的最短路径子图$G_1,G_2$,另外由$G_2$可以得到其反向图$G'_2$。然后分别在子图$G_1\cap G_2$和$G_1\cap G'_2$上进行拓扑排序求最长路径即可。本题最重要的就是从题面到数学语言的翻译过程了,如果这一点不明确,我们可能就会建立一个子图$G_1\cap(G_2\cup G'_2)$,这样就乱了。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <stack>
#include <cassert>
using namespace std;

const int MAX_NODE = 1510, MAX_EDGE = 200005, INF = 0x3f3f3f3f;

struct Node;
struct Edge;

struct Node
{
	int DistS, DistT;
	bool Done;
	int Dist;//Dijkstra时,它是临时的东东;TopSort时,它是真正的最长路径长度
	int DfsN;
	Edge *Head;
}_nodes[MAX_NODE];
int TotNode;

struct HeapNode
{
	Node *cur;
	int Dist;

	HeapNode(Node *x):cur(x),Dist(x->Dist){}

	bool operator < (const HeapNode& a) const
	{
		return Dist > a.Dist;
	}
};

struct Edge
{
	int Weight;
	bool InSPG;//在第一个人的最短路径子图中
	bool InTopG;//在Top子图中
	Node *To, *From;
	Edge *Next, *Rev;

	Edge() :InTopG(false), InSPG(false){}
}_edges[MAX_EDGE];
vector<Edge*> Temp;
int _eCount;

Edge *NewEdge()
{
	if (_eCount < MAX_EDGE - 1)
		return _edges + ++_eCount;
	else
	{
		Temp.push_back(new Edge());
		return Temp.back();
	}
}

Edge *AddEdge(Node *from, Node *to, int w)
{
	Edge *e = NewEdge();
	e->From = from;
	e->To = to;
	e->Weight = w;
	e->Next = from->Head;
	from->Head = e;
	return e;
}

void Build(int uId, int vId, int w)
{
	Node *u = _nodes + uId, *v = _nodes + vId;
	Edge *e1 = AddEdge(u, v, w), *e2 = AddEdge(v, u, w);
	e1->Rev = e2;
	e2->Rev = e1;
}

void Dijkstra(Node *start)
{
	static priority_queue<HeapNode> q;
	for (int i = 1; i <= TotNode; i++)
	{
		_nodes[i].Dist = INF;
		_nodes[i].Done = false;
	}
	start->Dist = 0;
	q.push(start);
	while (!q.empty())
	{
		HeapNode temp = q.top();
		q.pop();
		Node *cur = temp.cur;
		if (cur->Done)
			continue;
		cur->Done = true;
		for (Edge *e = cur->Head; e; e = e->Next)
		{
			if (cur->Dist + e->Weight < e->To->Dist)
			{
				e->To->Dist = cur->Dist + e->Weight;
				q.push(e->To);
			}
		}
	}
}

void GetInGraph(void(*DoInGraph)(Edge*), int spLen)
{
	for (int i = 1; i <= _eCount; i++)
		if (_edges[i].From->DistS + _edges[i].Weight + _edges[i].To->DistT == spLen)
			DoInGraph(_edges + i);
	for (int i = 0; i < Temp.size(); i++)
		if (Temp[i]->From->DistS + Temp[i]->Weight + Temp[i]->To->DistT == spLen)
			DoInGraph(Temp[i]);
}

void SetOrgGraph(Edge *e)
{
	e->InSPG = true;
}

void MakeTopGraph1(Edge *e)
{
	if (e->InSPG)
		e->InTopG = true;
}

void MakeTopGraph2(Edge *e)
{
	if (e->Rev->InSPG)
		e->InTopG = true;
}

int ShortestPath(int s, int t)
{
	Node *start = _nodes + s, *target = _nodes + t;
	Dijkstra(target);
	for (int i = 1; i <= TotNode; i++)
		_nodes[i].DistT = _nodes[i].Dist;
	Dijkstra(start);
	for (int i = 1; i <= TotNode; i++)
		_nodes[i].DistS = _nodes[i].Dist;
	return target->DistS;
}

void ClearTopGraph()
{
	for (int i = 1; i <= _eCount; i++)
		_edges[i].InTopG = false;
	for (int i = 0; i < Temp.size(); i++)
		Temp[i]->InTopG = false;
}

stack<Node*> St;
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)
	{
		if (!e->InTopG)
			continue;
		Dfs(e->To);
	}
	cur->DfsN = 2;
	St.push(cur);
}

int LongestPath()
{
	for (int i = 1; i <= TotNode; i++)
	{
		_nodes[i].Dist = 0;
		_nodes[i].DfsN = 0;
	}
	for (int i = 1; i <= TotNode; i++)
		Dfs(_nodes + i);
	int ans = 0;
	while (!St.empty())
	{
		Node *cur = St.top();
		St.pop();
		ans = max(ans, cur->Dist);
		for (Edge *e = cur->Head; e; e = e->Next)
			if (e->InTopG)
				e->To->Dist = max(e->To->Dist, cur->Dist + e->Weight);
	}
	return ans;
}

int main()
{
	int totEdge, s1, s2, t1, t2;
	scanf("%d%d%d%d%d%d", &TotNode, &totEdge, &s1, &t1, &s2, &t2);
	for (int i = 1; i <= totEdge; i++)
	{
		int u, v, w;
		scanf("%d%d%d", &u, &v, &w);
		Build(u, v, w);
	}
	int len1 = ShortestPath(s1, t1);
	GetInGraph(SetOrgGraph, len1);
	int len2 = ShortestPath(s2, t2);
	GetInGraph(MakeTopGraph1, len2);
	int ans1 = LongestPath();
	ClearTopGraph();
	GetInGraph(MakeTopGraph2, len2);
	int ans2 = LongestPath();
	printf("%d\n", max(ans1, ans2));
	return 0;
}

  

猜你喜欢

转载自www.cnblogs.com/headboy2002/p/9469277.html
今日推荐