UVA 11374 Airport Express 迪杰斯特拉算法

UVA 11374

题意:给你一个普通的无向带权图,再给你一个vip无向带权图,给你起点终点,要求普通图随便走,vip图只能走一条边,求起点到终点的最短路。

思路:vip图最多k=1000条边,如果枚举每条边并将其加入普通图求最短路,复杂度太高,可以这样想,先从起点求到每个点的最短路并用 g 数组保存,再从终点求每个点的最短路并用 f 数组保存,假如u,v是vip的一条路,那么ans=min(ans, dist(u,v)+g[u]+f[v], dist(u,v)+g[v]+f[u]),这样的话,总复杂度就是两次最短路的复杂度+k。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
const int maxn=500+5;
const int inf=1e8;
struct node
{
	int u,v,dist;
	bool friend operator<(node c,node d)
	{
		return c.dist>d.dist;
	}
}a[1000+5],no,ne;
vector<int>G[maxn],dis[maxn];
int pre1[maxn],pre2[maxn],g[maxn],f[maxn],vis[maxn];
int n,ans;
void init()
{
	for(int i=0;i<=n;i++)
	{
		G[i].clear();
		dis[i].clear();
		pre1[i]=pre2[i]=0;
	}	
}
void dij(int s,int e,int d[501],int pre[501],int flag)
{
	no.u=s;
	no.dist=0;
	priority_queue<node>q;
	q.push(no);
	for(int i=0;i<=n;i++)
	{
		vis[i]=pre[i]=0;
		d[i]=inf;
	}
	d[s]=0;
	while(!q.empty())
	{
		no=q.top();q.pop();
		int u=no.u;
		//d[u]=no.dist;
		if(u==e)
		ans=no.dist;
		if(vis[u])
		continue;	
		vis[u]=1;
		for(int i=0;i<G[u].size();i++)
		{
			int v=G[u][i];
			if(d[v]>d[u]+dis[u][i])
			{
				pre[v]=u;
				d[v]=no.dist+dis[u][i];
				ne.u=v;
				ne.dist=d[v];
				q.push(ne);	
			}
		}
	}
	if(flag==1)
	{
		for(int i=1;i<=n;i++)
		g[i]=d[i],pre1[i]=pre[i];
	}
	else
	{
		for(int i=1;i<=n;i++)
		f[i]=d[i],pre2[i]=pre[i];
	}
}
void print1(int u,int e)
{
	if(u!=e)
	{
		print1(pre1[u],e);
		printf(" %d",u);
	}
	else
	printf("%d",u);
}
void print2(int u,int e)
{
	if(u!=e)
	{
		printf("%d ",u);
		print2(pre2[u],e);
	}
	else
	printf("%d\n",u);
}
void work(int k,int s,int e)
{
	int flag1,flag2;
	flag1=flag2=0;
	for(int i=1;i<=k;i++)
	{
		int u=a[i].u;
		int v=a[i].v;
		int dist=a[i].dist;
		if(g[u]+f[v]+dist<ans)
		{
			ans=g[u]+f[v]+dist;
			flag1=u,flag2=v;
		}
		if(g[v]+f[u]+dist<ans)
		{
			ans=g[v]+f[u]+dist;
			flag1=v,flag2=u;
		}
	}
	if(!flag1)
	{
		print1(e,s);
		printf("\n");
		printf("Ticket Not Used\n");	
	}
	else
	{
		print1(flag1,s);
		printf(" ");
		print2(flag2,e);
		printf("%d\n",flag1);
	}
	printf("%d\n",ans);
}
int main()
{
	int s,e,kase=0;
	while(~scanf("%d%d%d",&n,&s,&e))
	{
		int i,m,k,u,v,z;
		if(kase++>0)
		printf("\n");
		init(); 
		scanf("%d",&m);
		while(m--)
		{
			scanf("%d%d%d",&u,&v,&z);
			G[u].push_back(v);
			G[v].push_back(u);
			dis[u].push_back(z);
			dis[v].push_back(z); 
		}
		scanf("%d",&k);
		for(i=1;i<=k;i++)
		scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].dist);
		dij(s,e,g,pre1,1);
		dij(e,s,f,pre2,2);
		work(k,s,e);
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

长沙橘子猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值