POJ - 3268 Silver Cow Party (往返最短路,Floyd,Dijkstra 2次优化)

 
题目传送门
 
题意:求往返最短路的最大值。
1、先想到Floyd结果超时了。
2、先用1次Dijkstra求出各点到X的距离,然后再用N-1次算出X到各点的距离。 485ms AC。
3、先用1次Dijkstra算各点到X的距离,然后用相反的邻接表的Dijkstra算出点X到各点的距。 0ms AC了!
 
直接Floyd:TLE
 
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int N, M, X;
const int MAXN = 1001, MAXM = 100001, INF = 0x3f3f3f3f;
//struct Edge
//{
//	int u, v, w;
//}e[MAXM];

int d[MAXN][MAXN];

void Floyd()
{
	for(int k = 1; k <= N; k++)
		for(int i = 1; i <= N; i++)
			for(int j = 1; j <= N; j++)
				if(d[i][k]+d[k][j] < d[i][j])
					d[i][j] = d[i][k]+d[k][j];
}

int main()
{
	scanf("%d%d%d", &N, &M, &X);
	memset(d, 0x3f, sizeof(d));
	for(int i = 0; i < M; i++)
	{
		//scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].w);
		int u, v, w;
		scanf("%d%d%d", &u, &v, &w);
		d[u][v] = w;
	}
	Floyd();
	int Max = 0;
	for(int i = 1; i <= N; i++)
	{
		int t = 0;
		if(i!=X)
			t = d[i][X] + d[X][i];
		if(t > Max)
			Max = t;
	}
	printf("%d\n", Max);
	return 0;
}

1 + N-1次Dijkstra :485ms
 
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <functional>
using namespace std;
int N, M, X;
const int MAXN = 1001, MAXM = 100001, INF = 0x3f3f3f3f;
struct Edge
{
	int u, v, w;
}edge[MAXM], edge1[MAXM];

typedef pair <int, int> P;
priority_queue<P, vector<P>, greater<P> > que;
int first[MAXN], nexte[MAXM];
int dis[MAXN], dis1[MAXN];
void Dijkstra(int s, int mod)
{
	int *f, *n, *d;
	Edge *e;
	f = first, n = nexte, e = edge;
	if(mod == 0)				//正向求n-1次到x的距离
		d = dis;
	else
		d = dis1;	//反向求x到个点的距离
	memset(d, 0x3f, sizeof(dis));
	d[s] = 0;
	que.push(make_pair(d[s], s));
	while(que.size())
	{
		P u = que.top(); que.pop();
		int x = u.second;		//起点
		if(u.first != d[x])		//计算过了,跳过
			continue;
		for(int i = f[x]; i != -1; i = n[i])		//松弛邻边
			if(d[x]+e[i].w < d[e[i].v])
			{
				d[e[i].v] = d[x] + e[i].w;
				que.push(make_pair(d[e[i].v], e[i].v));
			}
	}
}

int main()
{
	//freopen("in.txt", "r", stdin);
	scanf("%d%d%d", &N, &M, &X);
	//memset(d, 0x3f, sizeof(d));

	memset(first, -1, sizeof(first));
	for(int i = 0; i < M; i++)
	{
		scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].w);
		nexte[i] = first[edge[i].u];
		first[edge[i].u] = i;
	}
	
	Dijkstra(X, 1);
	int Max = 0;
	for(int i = 1; i <= N; i++)
		if(i!=X)
		{
			Dijkstra(i, 0);
			dis1[i] += dis[X];
			Max = max(dis1[i], Max);
		}
	printf("%d\n", Max);
	return 0;
}

2次Dijkstra:0ms
 
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <functional>
using namespace std;
int N, M, X;
const int MAXN = 1001, MAXM = 100001, INF = 0x3f3f3f3f;
struct Edge
{
	int u, v, w;
}edge[MAXM], edge1[MAXM];

typedef pair <int, int> P;
priority_queue<P, vector<P>, greater<P> > que;
int first[MAXN], nexte[MAXM], first1[MAXN], nexte1[MAXM];
int dis[MAXN], dis1[MAXN];
void Dijkstra(int s, int mod)
{
	int *f, *n, *d;
	Edge *e;
	if(mod == 0)				//正向求n-1次到x的距离
		f = first, n = nexte, d = dis, e = edge;
	else
		f = first1, n = nexte1, d = dis1, e = edge1;	//反向求x到个点的距离
	memset(d, 0x3f, sizeof(dis));
	d[s] = 0;
	que.push(make_pair(d[s], s));
	while(que.size())
	{
		P u = que.top(); que.pop();
		int x = u.second;		//起点
		if(u.first != d[x])		//计算过了,跳过
			continue;
		for(int i = f[x]; i != -1; i = n[i])		//松弛邻边
			if(d[x]+e[i].w < d[e[i].v])
			{
				d[e[i].v] = d[x] + e[i].w;
				que.push(make_pair(d[e[i].v], e[i].v));
			}
	}
}

int main()
{
	//freopen("in.txt", "r", stdin);
	scanf("%d%d%d", &N, &M, &X);

	memset(first, -1, sizeof(first));
	memset(first1, -1, sizeof(first1));
	for(int i = 0; i < M; i++)
	{
		scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].w);
		edge1[i].v = edge[i].u, edge1[i].u = edge[i].v, edge1[i].w = edge[i].w;
		nexte[i] = first[edge[i].u];
		first[edge[i].u] = i;
		//反方向
		nexte1[i] = first1[edge1[i].u];
		first1[edge1[i].u] = i;
	}
	
	Dijkstra(X, 1);
	int Max = 0;
	//for(int i = 1; i <= N; i++)
	//	if(i!=X)
	//	{
	//		Dijkstra(i, 0);
	//		dis1[i] += dis[X];
	//		Max = max(dis1[i], Max);
	//	}
	Dijkstra(X, 0);
	for(int i = 1; i <= N; i++)
		if(i!=X)
			Max = max(dis1[i]+dis[i], Max);

	printf("%d\n", Max);
	return 0;
}


 

                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值