POJ3268 牛的最长来回时间(单源最短路径)

有编号为1-N的牛,它们之间存在一些单向的路径。给定一头牛的编号,其他牛要去拜访它并且拜访完之后要返回自己原来的位置,求这些牛中所花的最长的来回时间是多少。

每头牛返回的最短时间很简单就可以算出来,这相当于从目标牛为起点求单源最短路径。但每头牛出发到目标牛的最短时间无法直接算出来,稍微转换一下,发现这个最短时间其实可以通过把所有的边取反向,然后再从目标牛求一次单源最短路径得到。得到这两个最短路径之后,取它们的和的最大者即可。

邻接阵O(n^2):

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <climits>
using namespace std;

const int N = 1005;
int edge[N][N];
int n, e, x;
int mindis1[N];
int mindis2[N];
bool vis1[N];
bool vis2[N];

void init()
{
	for (int i = 0; i < n; ++i) 
	{
		for (int j = 0; j < n; ++j)
		{
			edge[i][j] = -1;
		}
	}
}

void dijkstra(int s)
{
	int pos1, pos2, te1, te2, tm1, tm2;
	for (int i = 0; i < n; ++i) 
	{
		vis1[i] = false;
		vis2[i] = false;
		mindis1[i] = 999999;
		mindis2[i] = 999999;
	}
	mindis1[s] = 0;
	mindis2[s] = 0;
	vis1[s] = true;
	vis2[s] = true;
	pos1 = s;
	pos2 = s;
	for (int i = 0; i < n - 1; ++i)
	{
		for (int j = 0; j < n; ++j)
		{
			if (!vis1[j] && edge[pos1][j] != -1 &&  mindis1[pos1] + edge[pos1][j] < mindis1[j])
			{
				mindis1[j] = mindis1[pos1] +edge[pos1][j];
			}
			if (!vis2[j] && edge[j][pos2] != -1 && mindis2[pos2] + edge[j][pos2] < mindis2[j])
			{
				mindis2[j] = mindis2[pos2] + edge[j][pos2];
			}
		}
		tm1 = 999999;
		tm2 = 999999;
		for (int j = 0; j < n; ++j)
		{
			if (!vis1[j] && mindis1[j] < tm1)
			{
				tm1 = mindis1[j];
				te1 = j;
			}
			if (!vis2[j] && mindis2[j] < tm2)
			{
				tm2 = mindis2[j];
				te2 = j;
			}
		}
		vis1[te1] = true;
		pos1 = te1;
		vis2[te2] = true;
		pos2 = te2;
	}
}

int main()
{
	int beg, end, dis;
	scanf("%d%d%d", &n, &e, &x);
	init();
	for (int i = 0; i < e; ++i)
	{
		scanf("%d%d%d", &beg, &end, &dis);
		--beg;
		--end;
		edge[beg][end] = dis;
	}
	dijkstra(--x);
	int ans = 0;
	for (int i = 0; i < n; ++i)
	{
		if (i == x) continue;
		if (mindis1[i] + mindis2[i] > ans) ans = mindis1[i] + mindis2[i];
	}
	printf("%d\n", ans);
	return 0;
}

邻接表O(E*logE):

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
using namespace std;

const int N = 1005;
const int E = 1000005;
struct Edge
{
	int pnt;
	int dis;
	int next;
};
Edge edge1[E], edge2[E];
int cur1, cur2;
int neigh1[N], neigh2[N];
int n, e, x;
int mindis1[N];
int mindis2[N];
bool vis1[N];
bool vis2[N];
struct Qnode
{
	int pnt;
	int dis;
	Qnode(int _pnt, int _dis): pnt(_pnt), dis(_dis){}
	bool operator < (const Qnode& node) const
	{
		return dis > node.dis;
	}
};

void addedge(int beg, int end, int dis)
{
	edge1[cur1].pnt = end;
	edge1[cur1].dis = dis;
	edge1[cur1].next = neigh1[beg];
	neigh1[beg] = cur1;
	++cur1;

	edge2[cur2].pnt = beg;
	edge2[cur2].dis = dis;
	edge2[cur2].next = neigh2[end];
	neigh2[end] = cur2;
	++cur2;
}

void dijkstra(int s)
{
	int pre1, pre2, te1, te2, pnt1, pnt2;
	priority_queue<Qnode> pq1, pq2;
	for (int i = 0; i < n; ++i) 
	{
		vis1[i] = false;
		vis2[i] = false;
		mindis1[i] = 999999;
		mindis2[i] = 999999;
	}
	mindis1[s] = 0;
	mindis2[s] = 0;
	vis1[s] = true;
	vis2[s] = true;
	pq1.push(Qnode(s, 0));
	pq2.push(Qnode(s, 0));
	pre1 = s;
	pre2 = s;
	for (int i = 0; i < n - 1; ++i)
	{
		te1 = neigh1[pre1];
		while (te1 != -1)
		{
			pnt1 = edge1[te1].pnt;
			if (!vis1[pnt1] && mindis1[pre1] + edge1[te1].dis < mindis1[pnt1])
			{
				mindis1[pnt1] = mindis1[pre1] + edge1[te1].dis;
				pq1.push(Qnode(pnt1, mindis1[pnt1]));
			}
			te1 = edge1[te1].next;
		}
		while (!pq1.empty() && vis1[pq1.top().pnt]) pq1.pop();
		pre1 = pq1.top().pnt;
		vis1[pre1] = true;
		pq1.pop();

		te2 = neigh2[pre2];
		while (te2 != -1)
		{
			pnt2 = edge2[te2].pnt;
			if (!vis2[pnt2] && mindis2[pre2] + edge2[te2].dis < mindis2[pnt2])
			{
				mindis2[pnt2] = mindis2[pre2] + edge2[te2].dis;
				pq2.push(Qnode(pnt2, mindis2[pnt2]));
			}
			te2 = edge2[te2].next;
		}
		while (!pq2.empty() && vis2[pq2.top().pnt]) pq2.pop();
		pre2 = pq2.top().pnt;
		vis2[pre2] = true;
		pq2.pop();
	}
}

int main()
{
	int beg, end, dis;
	scanf("%d%d%d", &n, &e, &x);
	for (int i = 0; i < n; ++i) 
	{
		neigh1[i] = -1;
		neigh2[i] = -1;
	}
	cur1 = cur2 = 0;
	for (int i = 0; i < e; ++i)
	{
		scanf("%d%d%d", &beg, &end, &dis);
		--beg;
		--end;
		addedge(beg, end, dis);
	}
	dijkstra(--x);
	int ans = 0;
	for (int i = 0; i < n; ++i)
	{
		if (i == x) continue;
		if (mindis1[i] + mindis2[i] > ans) ans = mindis1[i] + mindis2[i];
	}
	printf("%d\n", ans);
	return 0;
}


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值