POJ3268 Silver Cow Party (最短路变形,反向 Dijktra)

题意:

给出一个有向图,n 个农庄,每个农庄有 1 头牛,m 条道路,每条道路花费 T 时间。有 n-1 头牛要去给 x 号农庄的牛过party,且要返回,每头牛要走最小时间的路,问所有牛中花费最大时间的那头牛的时间。

数据范围:

1 ≤ N ≤ 1000 1 ≤ N ≤ 1000 1N1000, 1 ≤ M ≤ 100 , 000 1 ≤ M ≤ 100,000 1M100,000

思路:

因为是有向图,起先想着:去时给每头牛来个 dijkstra,回来时给 x x x 来个dijkstra,可是用二维数组存图,最短路的时间复杂度就要 O ( n 2 ) O(n^2) O(n2) 再遍历每头牛,就要 O ( n 3 ) O(n^3) O(n3) ,不行,复杂度太大了。再深入思考,朴素的Dijkstra 是单源多终点,仅仅能解决回来时的情况,而去时的情况是多源单终点,问题是要求 1 − > 2 , 3 − > 2 , 4 − > 2 1->2,3->2,4->2 1>2,3>2,4>2的最短距离,这就等价于,如果一开始的时候给我的图是 2 − > 1 , 2 − > 3 , 2 − > 4 2->1,2->3,2->4 2>1,2>3,2>4就好了,所以想到了用转置矩阵mp[i][j]=mp[j][i]

输入:
4 8 2
1 2 4
1 3 2
1 4 7
2 1 1
2 3 5
3 1 2
3 4 4
4 2 3
输出:
10

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N =1010;
const int inf = 0x3f3f3f3f;
int n,m,x;
int mp[N][N];
int dist[N],ans[N];
bool vis[N];
int findMin()
{
	int k,mn=inf;
	for(int i=1;i<=n;i++)
	{
		if(!vis[i]&&dist[i]<mn)
		{
			mn=dist[i];
			k=i;
		}
	}
	return k;
}
void dij(int u) //板子 
{
	memset(dist,inf,sizeof dist);
	memset(vis,false,sizeof vis);
	for(int i=1;i<=n;i++)
		dist[i]=mp[u][i];
	dist[u]=0;
	vis[u]=true;
	for(int i=1;i<n;i++)
	{
		int tmp=findMin();
		vis[tmp]=true;
		for(int j=1;j<=n;j++)
			if(!vis[j] && dist[j]>dist[tmp]+mp[tmp][j])
				dist[j]=dist[tmp]+mp[tmp][j];
	}
}
void Trans()//转置矩阵
{
	for(int i=1;i<=n;i++)
		for(int j=1;j<i;j++)
			swap(mp[i][j],mp[j][i]);
} 
int main()
{
	cin>>n>>m>>x;
	int u,v,t;
	memset(mp,inf,sizeof mp); //初始化图 
	memset(ans,0,sizeof ans);
	while(m--)
	{
		scanf("%d %d %d",&u,&v,&t);
		mp[u][v]=t;
	}
	dij(x); //从农场 x 回来时的最小距离 
	for(int i=1;i<=n;i++)
		ans[i]=dist[i];
	Trans();
	dij(x);  //转置后 就是每头牛去时的最小距离 
	int mx=-inf;
	for(int i=1;i<=n;i++)  //找出花费的最大时间 mx 
	{
		ans[i]+=dist[i];
		if(mx<ans[i])
			mx=ans[i];
	}	
	printf("%d\n",mx);
	return 0;
} 
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值