POJ 3268 Silver Cow Party (dijkstra)

题意:给出一个单向带权图和一个点s,求点u,u到s的最短路径和s到u的最短路径之和最大。

思路:

对于s到任意点的最短路,直接dijkstra可以求出。

对于任意点到s的最短路,将所有边反向然后求一次最短路。容易证明,求出的s到任意点v的最短路s-->v就是原来没有反向的图的v-->s的最短路。

所以先求一次dijkstra,保存此次的结果,然后把所有的边反向,权值不变,再求一次dijkstra,将两次结果加起来,计算它们之中的最大值。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 1010
#define inf 0x3f3f3f3f
using namespace std;

int n, m;
int value[maxn][maxn];
int dis[maxn];
bool vis[maxn];
int dis2[maxn];

void dijkstra(int s) 
{
	memset(vis, false, sizeof(vis));
	for (int i = 1; i <= n; i++) dis[i] = inf;
	dis[s] = 0;

	while(true) 
	{
		int v = -1;
		for (int j = 1; j <= n; j++) 
		{
			if (!vis[j] && (v == -1 || dis[j]< dis[v])) v = j;
		}
		if (v == -1) break;
		vis[v] = true;
		for (int j = 1; j <= n; j++) 
		{
			if (dis[j] > dis[v] + value[v][j]) 
			{
				dis[j] = dis[v] + value[v][j];
			}
		}
	}
}

void dijkstra2(int s) 
{
	memset(vis, false, sizeof(vis));
	for (int i = 1; i <= n; i++) dis2[i] = inf;
	dis2[s] = 0;

	while (true)
	{
		int v = -1;
		for (int j = 1; j <= n; j++)
		{
			if (!vis[j] && (v == -1 || dis2[j]< dis2[v])) v = j;
		}
		if (v == -1) break;
		vis[v] = true;
		for (int j = 1; j <= n; j++)
		{
			if (dis2[j] > dis2[v] + value[j][v])
			{
				dis2[j] = dis2[v] + value[j][v];
			}
		}
	}
}

int main()
{
	int aim;
	while (scanf("%d %d %d", &n, &m, &aim) != EOF)
	{
		for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
			value[i][j] = inf;
		while (m--)
		{
			int u, v, w; cin >> u >> v >> w;
			if (w < value[u][v]) value[u][v] = w;
		}

		dijkstra(aim);
		dijkstra2(aim);

		int ans = 0;
		for (int i = 1; i <= n; i++) 
			if (dis[i] != inf && dis2[i] != inf)
				ans = max(ans, dis[i] + dis2[i]);

		printf("%d\n", ans);
	}

	return 0;
}

注:这里的dijkstra用的是一般方法,复杂度(V^2),也可以用最小堆(优先队列)处理,复杂度(E log(V))

posted @ 2017-08-18 15:25  demianzhang  阅读(162)  评论(0编辑  收藏  举报